diff options
author | Kurt Korbatits <kurt.korbatits@nokia.com> | 2010-01-07 23:30:02 (GMT) |
---|---|---|
committer | Kurt Korbatits <kurt.korbatits@nokia.com> | 2010-01-07 23:30:02 (GMT) |
commit | 3f3e86d6fce5bb781bc41def35d0f15c58ef769c (patch) | |
tree | f79a0317d168a1961c11c2b8f3b772029e2902e1 /src | |
parent | dbbf451755d34be44f6b7ac2e7c03ffe5528fb1b (diff) | |
parent | a3c1b0703575ed5fc364011c73dc104ecdb8ef0c (diff) | |
download | Qt-3f3e86d6fce5bb781bc41def35d0f15c58ef769c.zip Qt-3f3e86d6fce5bb781bc41def35d0f15c58ef769c.tar.gz Qt-3f3e86d6fce5bb781bc41def35d0f15c58ef769c.tar.bz2 |
Merge branch '4.6' of git@scm.dev.nokia.troll.no:qt/qt-multimedia-team into 4.6
Diffstat (limited to 'src')
245 files changed, 7140 insertions, 3888 deletions
diff --git a/src/3rdparty/easing/easing.cpp b/src/3rdparty/easing/easing.cpp index 81af40f..7d70a4d 100644 --- a/src/3rdparty/easing/easing.cpp +++ b/src/3rdparty/easing/easing.cpp @@ -252,7 +252,7 @@ static qreal easeOutInQuint(qreal t) */ static qreal easeInSine(qreal t) { - return (t == 1.0) ? 1.0 : -::cos(t * M_PI_2) + 1.0; + return (t == 1.0) ? 1.0 : -::qCos(t * M_PI_2) + 1.0; } /** @@ -263,7 +263,7 @@ static qreal easeInSine(qreal t) */ static qreal easeOutSine(qreal t) { - return ::sin(t* M_PI_2); + return ::qSin(t* M_PI_2); } /** @@ -274,7 +274,7 @@ static qreal easeOutSine(qreal t) */ static qreal easeInOutSine(qreal t) { - return -0.5 * (::cos(M_PI*t) - 1); + return -0.5 * (::qCos(M_PI*t) - 1); } /** @@ -397,15 +397,15 @@ static qreal easeInElastic_helper(qreal t, qreal b, qreal c, qreal d, qreal a, q if (t_adj==1) return b+c; qreal s; - if(a < ::fabs(c)) { + if(a < ::qFabs(c)) { a = c; s = p / 4.0f; } else { - s = p / (2 * M_PI) * ::asin(c / a); + s = p / (2 * M_PI) * ::qAsin(c / a); } t_adj -= 1.0f; - return -(a*::qPow(2.0f,10*t_adj) * ::sin( (t_adj*d-s)*(2*M_PI)/p )) + b; + return -(a*::qPow(2.0f,10*t_adj) * ::qSin( (t_adj*d-s)*(2*M_PI)/p )) + b; } /** @@ -431,10 +431,10 @@ static qreal easeOutElastic_helper(qreal t, qreal /*b*/, qreal c, qreal /*d*/, q a = c; s = p / 4.0f; } else { - s = p / (2 * M_PI) * ::asin(c / a); + s = p / (2 * M_PI) * ::qAsin(c / a); } - return (a*::qPow(2.0f,-10*t) * ::sin( (t-s)*(2*M_PI)/p ) + c); + return (a*::qPow(2.0f,-10*t) * ::qSin( (t-s)*(2*M_PI)/p ) + c); } /** @@ -469,11 +469,11 @@ static qreal easeInOutElastic(qreal t, qreal a, qreal p) a = 1.0; s = p / 4.0f; } else { - s = p / (2 * M_PI) * ::asin(1.0 / a); + s = p / (2 * M_PI) * ::qAsin(1.0 / a); } - if (t < 1) return -.5*(a*::qPow(2.0f,10*(t-1)) * ::sin( (t-1-s)*(2*M_PI)/p )); - return a*::qPow(2.0f,-10*(t-1)) * ::sin( (t-1-s)*(2*M_PI)/p )*.5 + 1.0; + if (t < 1) return -.5*(a*::qPow(2.0f,10*(t-1)) * ::qSin( (t-1-s)*(2*M_PI)/p )); + return a*::qPow(2.0f,-10*(t-1)) * ::qSin( (t-1-s)*(2*M_PI)/p )*.5 + 1.0; } /** diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-hebrew.c b/src/3rdparty/harfbuzz/src/harfbuzz-hebrew.c index 2bda386..67029be 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-hebrew.c +++ b/src/3rdparty/harfbuzz/src/harfbuzz-hebrew.c @@ -56,8 +56,6 @@ HB_Bool HB_HebrewShape(HB_ShaperItem *shaper_item) assert(shaper_item->item.script == HB_Script_Hebrew); - HB_HeuristicSetGlyphAttributes(shaper_item); - #ifndef NO_OPENTYPE if (HB_SelectScript(shaper_item, hebrew_features)) { @@ -65,7 +63,7 @@ HB_Bool HB_HebrewShape(HB_ShaperItem *shaper_item) if (!HB_ConvertStringToGlyphIndices(shaper_item)) return FALSE; - + HB_HeuristicSetGlyphAttributes(shaper_item); HB_OpenTypeShape(shaper_item, /*properties*/0); return HB_OpenTypePosition(shaper_item, availableGlyphs, /*doLogClusters*/TRUE); } diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp b/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp index bfb03ab..bfc7bd4 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp +++ b/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp @@ -980,6 +980,7 @@ HB_Face HB_NewFace(void *font, HB_GetFontTableFunc tableFunc) HB_Stream gdefStream; gdefStream = getTableStream(font, tableFunc, TTAG_GDEF); + error = HB_Err_Not_Covered; if (!gdefStream || (error = HB_Load_GDEF_Table(gdefStream, &face->gdef))) { //DEBUG("error loading gdef table: %d", error); face->gdef = 0; @@ -987,6 +988,7 @@ HB_Face HB_NewFace(void *font, HB_GetFontTableFunc tableFunc) //DEBUG() << "trying to load gsub table"; stream = getTableStream(font, tableFunc, TTAG_GSUB); + error = HB_Err_Not_Covered; if (!stream || (error = HB_Load_GSUB_Table(stream, &face->gsub, face->gdef, gdefStream))) { face->gsub = 0; if (error != HB_Err_Not_Covered) { @@ -998,6 +1000,7 @@ HB_Face HB_NewFace(void *font, HB_GetFontTableFunc tableFunc) _hb_close_stream(stream); stream = getTableStream(font, tableFunc, TTAG_GPOS); + error = HB_Err_Not_Covered; if (!stream || (error = HB_Load_GPOS_Table(stream, &face->gpos, face->gdef, gdefStream))) { face->gpos = 0; DEBUG("error loading gpos table: %d", error); diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp index d7f5344..01f74ac 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/JSObject.cpp @@ -115,9 +115,17 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue valu return; for (JSObject* obj = this; ; obj = asObject(prototype)) { +#ifdef QT_BUILD_SCRIPT_LIB + PropertyDescriptor descriptor; + if (obj->getPropertyDescriptor(exec, propertyName, descriptor)) { + JSObject* setterFunc; + if ((descriptor.isAccessorDescriptor() && ((setterFunc = asObject(descriptor.setter())), true)) + || (descriptor.value().isGetterSetter() && ((setterFunc = asGetterSetter(descriptor.value())->setter()), true))) { +#else if (JSValue gs = obj->getDirect(propertyName)) { if (gs.isGetterSetter()) { - JSObject* setterFunc = asGetterSetter(gs)->setter(); + JSObject* setterFunc = asGetterSetter(gs)->setter(); +#endif if (!setterFunc) { throwSetterError(exec); return; diff --git a/src/3rdparty/webkit/JavaScriptCore/ChangeLog b/src/3rdparty/webkit/JavaScriptCore/ChangeLog index d7d2d57..a559d9b 100644 --- a/src/3rdparty/webkit/JavaScriptCore/ChangeLog +++ b/src/3rdparty/webkit/JavaScriptCore/ChangeLog @@ -1,3 +1,25 @@ +2009-12-08 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk> + + Reviewed by Darin Adler. + + Make WebKit build correctly on FreeBSD, IA64, and Alpha. + Based on work by Petr Salinger <Petr.Salinger@seznam.cz>, + and Colin Watson <cjwatson@ubuntu.com>. + + * wtf/Platform.h: + +2009-12-18 Yongjun Zhang <yongjun.zhang@nokia.com> + + Reviewed by Simon Hausmann. + + https://bugs.webkit.org/show_bug.cgi?id=32713 + [Qt] make wtf/Assertions.h compile in winscw compiler. + + Add string arg before ellipsis to help winscw compiler resolve variadic + macro definitions in wtf/Assertions.h. + + * wtf/Assertions.h: + 2009-11-30 Jan-Arve Sæther <jan-arve.saether@nokia.com> Reviewed by Simon Hausmann. diff --git a/src/3rdparty/webkit/JavaScriptCore/wtf/Assertions.h b/src/3rdparty/webkit/JavaScriptCore/wtf/Assertions.h index f529a62..aa72e5a 100644 --- a/src/3rdparty/webkit/JavaScriptCore/wtf/Assertions.h +++ b/src/3rdparty/webkit/JavaScriptCore/wtf/Assertions.h @@ -158,8 +158,8 @@ void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChann #define ASSERT(assertion) ((void)0) #if COMPILER(MSVC7) #define ASSERT_WITH_MESSAGE(assertion) ((void)0) -#elif PLATFORM(SYMBIAN) -#define ASSERT_WITH_MESSAGE(assertion...) ((void)0) +#elif COMPILER(WINSCW) +#define ASSERT_WITH_MESSAGE(assertion, arg...) ((void)0) #else #define ASSERT_WITH_MESSAGE(assertion, ...) ((void)0) #endif /* COMPILER(MSVC7) */ @@ -176,8 +176,8 @@ void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChann while (0) #if COMPILER(MSVC7) #define ASSERT_WITH_MESSAGE(assertion) ((void)0) -#elif PLATFORM(SYMBIAN) -#define ASSERT_WITH_MESSAGE(assertion...) ((void)0) +#elif COMPILER(WINSCW) +#define ASSERT_WITH_MESSAGE(assertion, arg...) ((void)0) #else #define ASSERT_WITH_MESSAGE(assertion, ...) do \ if (!(assertion)) { \ @@ -219,11 +219,11 @@ while (0) /* FATAL */ -#if FATAL_DISABLED && !COMPILER(MSVC7) && !PLATFORM(SYMBIAN) +#if FATAL_DISABLED && !COMPILER(MSVC7) && !COMPILER(WINSCW) #define FATAL(...) ((void)0) #elif COMPILER(MSVC7) #define FATAL() ((void)0) -#elif PLATFORM(SYMBIAN) +#elif COMPILER(WINSCW) #define FATAL(args...) ((void)0) #else #define FATAL(...) do { \ @@ -234,24 +234,24 @@ while (0) /* LOG_ERROR */ -#if ERROR_DISABLED && !COMPILER(MSVC7) && !PLATFORM(SYMBIAN) +#if ERROR_DISABLED && !COMPILER(MSVC7) && !COMPILER(WINSCW) #define LOG_ERROR(...) ((void)0) #elif COMPILER(MSVC7) #define LOG_ERROR() ((void)0) -#elif PLATFORM(SYMBIAN) -#define LOG_ERROR(args...) ((void)0) +#elif COMPILER(WINSCW) +#define LOG_ERROR(arg...) ((void)0) #else #define LOG_ERROR(...) WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, __VA_ARGS__) #endif /* LOG */ -#if LOG_DISABLED && !COMPILER(MSVC7) && !PLATFORM(SYMBIAN) +#if LOG_DISABLED && !COMPILER(MSVC7) && !COMPILER(WINSCW) #define LOG(channel, ...) ((void)0) #elif COMPILER(MSVC7) #define LOG() ((void)0) -#elif PLATFORM(SYMBIAN) -#define LOG(channel, args...) ((void)0) +#elif COMPILER(WINSCW) +#define LOG(arg...) ((void)0) #else #define LOG(channel, ...) WTFLog(&JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__) #define JOIN_LOG_CHANNEL_WITH_PREFIX(prefix, channel) JOIN_LOG_CHANNEL_WITH_PREFIX_LEVEL_2(prefix, channel) @@ -260,12 +260,12 @@ while (0) /* LOG_VERBOSE */ -#if LOG_DISABLED && !COMPILER(MSVC7) && !PLATFORM(SYMBIAN) +#if LOG_DISABLED && !COMPILER(MSVC7) && !COMPILER(WINSCW) #define LOG_VERBOSE(channel, ...) ((void)0) #elif COMPILER(MSVC7) #define LOG_VERBOSE(channel) ((void)0) -#elif PLATFORM(SYMBIAN) -#define LOG_VERBOSE(channel, args...) ((void)0) +#elif COMPILER(WINSCW) +#define LOG_VERBOSE(channel, arg...) ((void)0) #else #define LOG_VERBOSE(channel, ...) WTFLogVerbose(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, &JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__) #endif diff --git a/src/3rdparty/webkit/JavaScriptCore/wtf/Platform.h b/src/3rdparty/webkit/JavaScriptCore/wtf/Platform.h index cb6c9b9..3e1093b 100644 --- a/src/3rdparty/webkit/JavaScriptCore/wtf/Platform.h +++ b/src/3rdparty/webkit/JavaScriptCore/wtf/Platform.h @@ -347,6 +347,16 @@ #define WTF_PLATFORM_X86_64 1 #endif +/* PLATFORM(IA64) */ +#if defined(__ia64__) +#define WTF_PLATFORM_IA64 1 +#endif + +/* PLATFORM(ALPHA) */ +#if defined(__alpha__) +#define WTF_PLATFORM_ALPHA 1 +#endif + /* PLATFORM(SH4) */ #if defined(__SH4__) #define WTF_PLATFORM_SH4 1 @@ -709,7 +719,7 @@ #endif #if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) -#if PLATFORM(X86_64) && (PLATFORM(DARWIN) || PLATFORM(LINUX) || PLATFORM(WIN_OS)) +#if (PLATFORM(X86_64) && (PLATFORM(UNIX) || PLATFORM(WIN_OS))) || PLATFORM(IA64) || PLATFORM(ALPHA) #define WTF_USE_JSVALUE64 1 #elif PLATFORM(ARM) || PLATFORM(PPC64) #define WTF_USE_JSVALUE32 1 diff --git a/src/3rdparty/webkit/VERSION b/src/3rdparty/webkit/VERSION index 62acbdf..70913ca 100644 --- a/src/3rdparty/webkit/VERSION +++ b/src/3rdparty/webkit/VERSION @@ -8,4 +8,4 @@ The commit imported was from the and has the sha1 checksum - 9de63cde0ac8aa08e207d4ffce2846df1a44a364 + 865abd2871c801c1d3d0f4eebd985b2daab89ebe diff --git a/src/3rdparty/webkit/WebCore/ChangeLog b/src/3rdparty/webkit/WebCore/ChangeLog index 4f6146f..e72293d 100644 --- a/src/3rdparty/webkit/WebCore/ChangeLog +++ b/src/3rdparty/webkit/WebCore/ChangeLog @@ -1,3 +1,109 @@ +2010-01-06 Simon Hausmann <simon.hausmann@nokia.com> + + Unreviewed trivial Qt build fix. + + Prefix the phonon includes with phonon/ to avoid conflicts with the S60 + audio routing API ( http://wiki.forum.nokia.com/index.php/Audio_Routing_API ). + + * platform/graphics/qt/MediaPlayerPrivatePhonon.cpp: + +2009-12-31 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + Do not include Frame.h under WebCore/html/canvas + https://bugs.webkit.org/show_bug.cgi?id=33082 + + No new tests, as there is no new functionality. + + * html/canvas/CanvasRenderingContext2D.cpp: + +2009-12-30 Janne Koskinen <janne.p.koskinen@digia.com> + + Reviewed by Simon Hausmann. + + [Qt] Add support for Symbian def files + + * WebCore.pro: + +2009-12-30 Simon Hausmann <simon.hausmann@nokia.com> + + Unreviewed Qt/Symbian build fix. + + Don't build network state notifier support when building inside of Qt. + Otherwise the Qt build depends on an external module that itself depends + on Qt again. + + * WebCore.pro: + +2009-12-30 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Simon Hausmann. + + Turn off DataGrid support by default. + + No new tests, as there is no new functionality. + + * WebCore.pro: + +2009-12-17 Yael Aharon <yael.aharon@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] support navigator.onLine and ononline/onoffline events. + https://bugs.webkit.org/show_bug.cgi?id=32555 + + Hooked up Bearer Management to NetworkStateNotifier. This solution is available + only if QtMobility's Bearer Management is installed. + + * WebCore.pro: + * platform/network/NetworkStateNotifier.h: + * platform/network/qt/NetworkStateNotifierPrivate.h: Added. + * platform/network/qt/NetworkStateNotifierQt.cpp: Added. + (WebCore::NetworkStateNotifierPrivate::NetworkStateNotifierPrivate): + (WebCore::NetworkStateNotifierPrivate::onlineStateChanged): + (WebCore::NetworkStateNotifierPrivate::~NetworkStateNotifierPrivate): + (WebCore::NetworkStateNotifier::updateState): + (WebCore::NetworkStateNotifier::NetworkStateNotifier): + +2009-12-17 Simon Hausmann <simon.hausmann@nokia.com> + + Reviewed by Tor Arne Vestbø. + + [Qt] Symbian build fix: Don't include QtXml/qxmlstream.h but omit the prefix, to + make sure we pick up the header file from QtCore. That is where the implementation + is compiled. + + * dom/XMLTokenizer.h: + +2009-12-14 Holger Hans Peter Freyther <zecke@selfish.org> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Add manual test for JavaScript prompt corner case + https://bugs.webkit.org/show_bug.cgi?id=30914 + + The patch is based on the work done by Gupta Manish. + + Verify behavior of the JavaScript prompt function. Currently + Qt is not behaving like other WebKit ports and Firefox in + regards to accepting the prompt but not entering a text. + + * manual-tests/qt/java-script-prompt.html: Added. + +2009-12-21 Andreas Kling <andreas.kling@nokia.com> + + Reviewed by Darin Adler. + + Fix assertion failure when dragging an SVG image. + https://bugs.webkit.org/show_bug.cgi?id=32511 + + Test: fast/images/drag-svg-as-image.html + + * svg/graphics/SVGImage.cpp: + (WebCore::SVGImage::filenameExtension): Return "svg" + * svg/graphics/SVGImage.h: + 2009-11-23 Simon Hausmann <simon.hausmann@nokia.com> Reviewed by Kenneth Rohde Christiansen. diff --git a/src/3rdparty/webkit/WebCore/WebCore.pro b/src/3rdparty/webkit/WebCore/WebCore.pro index 9239089..be64e3b 100644 --- a/src/3rdparty/webkit/WebCore/WebCore.pro +++ b/src/3rdparty/webkit/WebCore/WebCore.pro @@ -136,7 +136,7 @@ contains(DEFINES, ENABLE_SINGLE_THREADED=1) { !contains(DEFINES, ENABLE_SHARED_WORKERS=.): DEFINES += ENABLE_SHARED_WORKERS=1 !contains(DEFINES, ENABLE_WORKERS=.): DEFINES += ENABLE_WORKERS=1 !contains(DEFINES, ENABLE_XHTMLMP=.): DEFINES += ENABLE_XHTMLMP=0 -!contains(DEFINES, ENABLE_DATAGRID=.): DEFINES += ENABLE_DATAGRID=1 +!contains(DEFINES, ENABLE_DATAGRID=.): DEFINES += ENABLE_DATAGRID=0 # SVG support !contains(DEFINES, ENABLE_SVG=0) { @@ -180,6 +180,15 @@ contains(DEFINES, ENABLE_SINGLE_THREADED=1) { else:DEFINES += ENABLE_XSLT=0 } +!CONFIG(QTDIR_build):!contains(DEFINES, ENABLE_QT_BEARER=.) { + symbian: { + exists($${EPOCROOT}epoc32/release/winscw/udeb/QtBearer.lib)| \ + exists($${EPOCROOT}epoc32/release/armv5/lib/QtBearer.lib) { + DEFINES += ENABLE_QT_BEARER=1 + } + } +} + DEFINES += WTF_USE_JAVASCRIPTCORE_BINDINGS=1 WTF_CHANGES=1 # Used to compute defaults for the build-webkit script @@ -2860,6 +2869,17 @@ contains(DEFINES, ENABLE_XHTMLMP=1) { FEATURE_DEFINES_JAVASCRIPT += ENABLE_XHTMLMP=1 } +contains(DEFINES, ENABLE_QT_BEARER=1) { + HEADERS += \ + platform/network/qt/NetworkStateNotifierPrivate.h + + SOURCES += \ + platform/network/qt/NetworkStateNotifierQt.cpp + + LIBS += -lQtBearer + +} + contains(DEFINES, ENABLE_SVG=1) { FEATURE_DEFINES_JAVASCRIPT += ENABLE_SVG=1 @@ -3382,16 +3402,15 @@ CONFIG(QTDIR_build):isEqual(QT_MAJOR_VERSION, 4):greaterThan(QT_MINOR_VERSION, 4 } } -# Temporary workaround to pick up the DEF file from the same place as all the others symbian { shared { contains(MMP_RULES, defBlock) { MMP_RULES -= defBlock MMP_RULES += "$${LITERAL_HASH}ifdef WINSCW" \ - "DEFFILE ../../../s60installs/bwins/$${TARGET}.def" \ + "DEFFILE ../WebKit/qt/symbian/bwins/$${TARGET}.def" \ "$${LITERAL_HASH}elif defined EABI" \ - "DEFFILE ../../../s60installs/eabi/$${TARGET}.def" \ + "DEFFILE ../WebKit/qt/symbian/eabi/$${TARGET}.def" \ "$${LITERAL_HASH}endif" } } diff --git a/src/3rdparty/webkit/WebCore/dom/XMLTokenizer.h b/src/3rdparty/webkit/WebCore/dom/XMLTokenizer.h index e1ee09f..a83e73a 100644 --- a/src/3rdparty/webkit/WebCore/dom/XMLTokenizer.h +++ b/src/3rdparty/webkit/WebCore/dom/XMLTokenizer.h @@ -34,7 +34,7 @@ #include <wtf/OwnPtr.h> #if USE(QXMLSTREAM) -#include <QtXml/qxmlstream.h> +#include <qxmlstream.h> #else #include <libxml/tree.h> #include <libxml/xmlstring.h> diff --git a/src/3rdparty/webkit/WebCore/html/canvas/CanvasRenderingContext2D.cpp b/src/3rdparty/webkit/WebCore/html/canvas/CanvasRenderingContext2D.cpp index 3341901..848771b 100644 --- a/src/3rdparty/webkit/WebCore/html/canvas/CanvasRenderingContext2D.cpp +++ b/src/3rdparty/webkit/WebCore/html/canvas/CanvasRenderingContext2D.cpp @@ -42,7 +42,6 @@ #include "Document.h" #include "ExceptionCode.h" #include "FloatConversion.h" -#include "Frame.h" #include "GraphicsContext.h" #include "HTMLCanvasElement.h" #include "HTMLImageElement.h" diff --git a/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp index 9faa234..7a78391 100644 --- a/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp +++ b/src/3rdparty/webkit/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp @@ -38,12 +38,10 @@ #include <QUrl> #include <QEvent> -#if defined (__SYMBIAN32__) #include <phonon/path.h> -#endif -#include <audiooutput.h> -#include <mediaobject.h> -#include <videowidget.h> +#include <phonon/audiooutput.h> +#include <phonon/mediaobject.h> +#include <phonon/videowidget.h> using namespace Phonon; diff --git a/src/3rdparty/webkit/WebCore/platform/network/NetworkStateNotifier.h b/src/3rdparty/webkit/WebCore/platform/network/NetworkStateNotifier.h index 0189f5f..f8c5654 100644 --- a/src/3rdparty/webkit/WebCore/platform/network/NetworkStateNotifier.h +++ b/src/3rdparty/webkit/WebCore/platform/network/NetworkStateNotifier.h @@ -46,6 +46,10 @@ typedef const struct __SCDynamicStore * SCDynamicStoreRef; namespace WebCore { +#if (PLATFORM(QT) && ENABLE(QT_BEARER)) +class NetworkStateNotifierPrivate; +#endif + class NetworkStateNotifier { public: NetworkStateNotifier(); @@ -78,10 +82,14 @@ private: #elif PLATFORM(CHROMIUM) NetworkStateNotifierPrivate p; + +#elif PLATFORM(QT) && ENABLE(QT_BEARER) + friend class NetworkStateNotifierPrivate; + NetworkStateNotifierPrivate* p; #endif }; -#if !PLATFORM(MAC) && !PLATFORM(WIN) && !PLATFORM(CHROMIUM) +#if !PLATFORM(MAC) && !PLATFORM(WIN) && !PLATFORM(CHROMIUM) && !(PLATFORM(QT) && ENABLE(QT_BEARER)) inline NetworkStateNotifier::NetworkStateNotifier() : m_isOnLine(true) diff --git a/src/3rdparty/webkit/WebCore/platform/network/qt/NetworkStateNotifierPrivate.h b/src/3rdparty/webkit/WebCore/platform/network/qt/NetworkStateNotifierPrivate.h new file mode 100644 index 0000000..7af6392 --- /dev/null +++ b/src/3rdparty/webkit/WebCore/platform/network/qt/NetworkStateNotifierPrivate.h @@ -0,0 +1,49 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef NetworkStateNotifierPrivate_h +#define NetworkStateNotifierPrivate_h + +#include <QObject> + +namespace QtMobility { +class QNetworkConfigurationManager; +} + +namespace WebCore { + +class NetworkStateNotifier; + +class NetworkStateNotifierPrivate : public QObject { + Q_OBJECT +public: + NetworkStateNotifierPrivate(NetworkStateNotifier* notifier); + ~NetworkStateNotifierPrivate(); +public slots: + void onlineStateChanged(bool); + +public: + QtMobility::QNetworkConfigurationManager* m_configurationManager; + bool m_online; + NetworkStateNotifier* m_notifier; +}; + +} // namespace WebCore + +#endif diff --git a/src/3rdparty/webkit/WebCore/platform/network/qt/NetworkStateNotifierQt.cpp b/src/3rdparty/webkit/WebCore/platform/network/qt/NetworkStateNotifierQt.cpp new file mode 100644 index 0000000..f74398b --- /dev/null +++ b/src/3rdparty/webkit/WebCore/platform/network/qt/NetworkStateNotifierQt.cpp @@ -0,0 +1,73 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "NetworkStateNotifier.h" + +#include "NetworkStateNotifierPrivate.h" +#include "qnetworkconfigmanager.h" + +using namespace QtMobility; + +namespace WebCore { + +NetworkStateNotifierPrivate::NetworkStateNotifierPrivate(NetworkStateNotifier* notifier) + : m_configurationManager(new QNetworkConfigurationManager()) + , m_online(m_configurationManager->isOnline()) + , m_notifier(notifier) +{ + Q_ASSERT(notifier); + connect(m_configurationManager, SIGNAL(onlineStateChanged(bool)), this, SLOT(onlineStateChanged(bool))); +} + +void NetworkStateNotifierPrivate::onlineStateChanged(bool isOnline) +{ + if (m_online == isOnline) + return; + + m_online = isOnline; + m_notifier->updateState(); +} + +NetworkStateNotifierPrivate::~NetworkStateNotifierPrivate() +{ + delete m_configurationManager; +} + +void NetworkStateNotifier::updateState() +{ + if (m_isOnLine == p->m_online) + return; + + m_isOnLine = p->m_online; + if (m_networkStateChangedFunction) + m_networkStateChangedFunction(); +} + +NetworkStateNotifier::NetworkStateNotifier() + : m_isOnLine(true) + , m_networkStateChangedFunction(0) +{ + p = new NetworkStateNotifierPrivate(this); + m_isOnLine = p->m_online; +} + +} // namespace WebCore + +#include "moc_NetworkStateNotifierPrivate.cpp" diff --git a/src/3rdparty/webkit/WebCore/svg/graphics/SVGImage.cpp b/src/3rdparty/webkit/WebCore/svg/graphics/SVGImage.cpp index 0a506f8..b74e912 100644 --- a/src/3rdparty/webkit/WebCore/svg/graphics/SVGImage.cpp +++ b/src/3rdparty/webkit/WebCore/svg/graphics/SVGImage.cpp @@ -267,6 +267,11 @@ bool SVGImage::dataChanged(bool allDataReceived) return m_page; } +String SVGImage::filenameExtension() const +{ + return "svg"; +} + } #endif // ENABLE(SVG) diff --git a/src/3rdparty/webkit/WebCore/svg/graphics/SVGImage.h b/src/3rdparty/webkit/WebCore/svg/graphics/SVGImage.h index 2cea91a..0f05429 100644 --- a/src/3rdparty/webkit/WebCore/svg/graphics/SVGImage.h +++ b/src/3rdparty/webkit/WebCore/svg/graphics/SVGImage.h @@ -47,6 +47,8 @@ namespace WebCore { private: virtual ~SVGImage(); + virtual String filenameExtension() const; + virtual void setContainerSize(const IntSize&); virtual bool usesContainerSize() const; virtual bool hasRelativeWidth() const; diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebinspector.cpp b/src/3rdparty/webkit/WebKit/qt/Api/qwebinspector.cpp index f43cbbf..1145744 100644 --- a/src/3rdparty/webkit/WebKit/qt/Api/qwebinspector.cpp +++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebinspector.cpp @@ -139,6 +139,9 @@ QSize QWebInspector::sizeHint() const /*! \reimp */ bool QWebInspector::event(QEvent* ev) { + if (ev->type() == QEvent::Close && d->page) + d->page->d->inspectorController()->setWindowVisible(false); + return QWidget::event(ev); } @@ -159,8 +162,6 @@ void QWebInspector::showEvent(QShowEvent* event) /*! \reimp */ void QWebInspector::hideEvent(QHideEvent* event) { - if (d->page) - d->page->d->inspectorController()->setWindowVisible(false); } /*! \internal */ diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp b/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp index 1bdc3ed..6d08c32 100644 --- a/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp +++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebpage.cpp @@ -1849,7 +1849,8 @@ bool QWebPage::javaScriptConfirm(QWebFrame *frame, const QString& msg) The program may provide an optional message, \a msg, as well as a default value for the input in \a defaultValue. If the prompt was cancelled by the user the implementation should return false; otherwise the - result should be written to \a result and true should be returned. + result should be written to \a result and true should be returned. If the prompt was not cancelled by the + user, the implementation should return true and the result string must not be null. The default implementation uses QInputDialog::getText. */ @@ -3080,7 +3081,7 @@ QString QWebPage::userAgentForUrl(const QUrl& url) const Q_UNUSED(url) QString ua = QLatin1String("Mozilla/5.0 (" - // Plastform + // Platform #ifdef Q_WS_MAC "Macintosh" #elif defined Q_WS_QWS @@ -3089,19 +3090,22 @@ QString QWebPage::userAgentForUrl(const QUrl& url) const "Windows" #elif defined Q_WS_X11 "X11" +#elif defined Q_OS_SYMBIAN + "SymbianOS" #else "Unknown" #endif - "; " + // Placeholder for Platform Version + "%1; " // Placeholder for security strength (N or U) - "%1; " + "%2; " // Subplatform" #ifdef Q_OS_AIX "AIX" #elif defined Q_OS_WIN32 - "%2" + "%3" #elif defined Q_OS_DARWIN #ifdef __i386__ || __x86_64__ "Intel Mac OS X" @@ -3153,6 +3157,8 @@ QString QWebPage::userAgentForUrl(const QUrl& url) const "Sun Solaris" #elif defined Q_OS_ULTRIX "DEC Ultrix" +#elif defined Q_WS_S60 + "Series60" #elif defined Q_OS_UNIX "UNIX BSD/SYSV system" #elif defined Q_OS_UNIXWARE @@ -3160,7 +3166,28 @@ QString QWebPage::userAgentForUrl(const QUrl& url) const #else "Unknown" #endif - "; "); + // Placeholder for SubPlatform Version + "%4; "); + + // Platform Version + QString osVer; +#ifdef Q_OS_SYMBIAN + QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion(); + switch (symbianVersion) { + case QSysInfo::SV_9_2: + osVer = "/9.2"; + break; + case QSysInfo::SV_9_3: + osVer = "/9.3"; + break; + case QSysInfo::SV_9_4: + osVer = "/9.4"; + break; + default: + osVer = "Unknown"; + } +#endif + ua = ua.arg(osVer); QChar securityStrength(QLatin1Char('N')); #if !defined(QT_NO_OPENSSL) @@ -3224,6 +3251,26 @@ QString QWebPage::userAgentForUrl(const QUrl& url) const ua = QString(ua).arg(ver); #endif + // SubPlatform Version + QString subPlatformVer; +#ifdef Q_OS_SYMBIAN + QSysInfo::S60Version s60Version = QSysInfo::s60Version(); + switch (s60Version) { + case QSysInfo::SV_S60_3_1: + subPlatformVer = "/3.1"; + break; + case QSysInfo::SV_S60_3_2: + subPlatformVer = "/3.2"; + break; + case QSysInfo::SV_S60_5_0: + subPlatformVer = "/5.0"; + break; + default: + subPlatformVer = " Unknown"; + } +#endif + ua = ua.arg(subPlatformVer); + // Language QLocale locale; if (view()) @@ -3407,9 +3454,9 @@ quint64 QWebPage::bytesReceived() const /*! \fn void QWebPage::unsupportedContent(QNetworkReply *reply) - This signals is emitted when webkit cannot handle a link the user navigated to. + This signal is emitted when WebKit cannot handle a link the user navigated to. - At signal emissions time the meta data of the QNetworkReply \a reply is available. + At signal emission time the meta-data of the QNetworkReply \a reply is available. \note This signal is only emitted if the forwardUnsupportedContent property is set to true. diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebview.h b/src/3rdparty/webkit/WebKit/qt/Api/qwebview.h index e9c1ec8..0f79c70 100644 --- a/src/3rdparty/webkit/WebKit/qt/Api/qwebview.h +++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebview.h @@ -51,12 +51,7 @@ class QWEBKIT_EXPORT QWebView : public QWidget { Q_PROPERTY(qreal textSizeMultiplier READ textSizeMultiplier WRITE setTextSizeMultiplier DESIGNABLE false) Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor) -// FIXME: temporary work around for elftran issue that it couldn't find the QPainter::staticMetaObject -// symbol from Qt lib; it should be reverted after the right symbol is exported. -// See bug: http://qt.nokia.com/developer/task-tracker/index_html?method=entry&id=258893 -#if defined(Q_QDOC) || !defined(Q_OS_SYMBIAN) Q_PROPERTY(QPainter::RenderHints renderHints READ renderHints WRITE setRenderHints) -#endif Q_FLAGS(QPainter::RenderHints) public: explicit QWebView(QWidget* parent = 0); diff --git a/src/3rdparty/webkit/WebKit/qt/ChangeLog b/src/3rdparty/webkit/WebKit/qt/ChangeLog index 2f0bf17..4ab5bfb 100644 --- a/src/3rdparty/webkit/WebKit/qt/ChangeLog +++ b/src/3rdparty/webkit/WebKit/qt/ChangeLog @@ -1,3 +1,89 @@ +2009-12-30 Janne Koskinen <janne.p.koskinen@digia.com> + + Reviewed by Simon Hausmann. + + Upstream Symbian def files from Qt 4.6. + + These files define the ABI of QtWebKit on Symbian. + + * symbian/bwins/QtWebKitu.def: Added. + * symbian/eabi/QtWebKitu.def: Added. + +2009-12-14 Holger Hans Peter Freyther <zecke@selfish.org> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Fix JavaScript prompt behavior for empty/null strings. + https://bugs.webkit.org/show_bug.cgi?id=30914 + + The patch is based on the work done by Gupta Manish. + + In the default implementation of the JavaScript prompt + we are using a QInputDialog to get the text and this has + one quirk with regard to not entering any text. + + In other WebKit ports and in Firefox an empty string is + returned but in the Qt case it is a null string. + + Change the API documentation in QWebPage to mention we want to + have a non null string but do the fixup in the ChromeClientQt + to support existing code. + + * Api/qwebpage.cpp: + (QWebPage::javaScriptPrompt): Change API documentation + * WebCoreSupport/ChromeClientQt.cpp: + (WebCore::ChromeClientQt::runJavaScriptPrompt): Fixup null QString + +2009-12-21 David Boddie <dboddie@trolltech.com> + + Reviewed by Simon Hausmann. + + Doc: Minor fixes to language. + + * Api/qwebpage.cpp: + +2009-12-15 Holger Hans Peter Freyther <zecke@selfish.org> + + Reviewed by NOBODY (OOPS!). + + [Qt] Do not disable the inspector on show and hide + https://bugs.webkit.org/show_bug.cgi?id=31851 + + On Qt/X11 with some window managers the window will be + hidden when switching windows. In this case all the results + are gone when coming back to the window. + + Attempt to use the CloseEvent to figure out if the window + was closed and withdrawn as this is more friendly to the + user of the inspector client. + + * Api/qwebinspector.cpp: + (QWebInspector::event): + (QWebInspector::hideEvent): + +2009-12-13 Simon Hausmann <hausmann@webkit.org> + + Reviewed by Holger Freyther. + + [Qt] Re-enable QWebView::renderHints property for Qt for Symbian + + https://bugs.webkit.org/show_bug.cgi?id=28273 + + The bug in Qt's moc that triggered a linking error when declaring this + property has been fixed and we can remove the workaround. + + * Api/qwebview.h: + +2009-11-30 Abhinav Mithal <abhinav.mithal@nokia.com> + + Reviewed by Simon Hausmann. + + [Qt][Symbian] Report SymbianOS in user agent string for Symbian + https://bugs.webkit.org/show_bug.cgi?id=31961 + + * Api/qwebpage.cpp: + (QWebPage::userAgentForUrl): + 2009-11-28 Simon Hausmann <simon.hausmann@nokia.com> Reviewed by Kenneth Rohde Christiansen. diff --git a/src/3rdparty/webkit/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp b/src/3rdparty/webkit/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp index 26cf6f6..c5d2792 100644 --- a/src/3rdparty/webkit/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp +++ b/src/3rdparty/webkit/WebKit/qt/WebCoreSupport/ChromeClientQt.cpp @@ -278,7 +278,14 @@ bool ChromeClientQt::runJavaScriptPrompt(Frame* f, const String& message, const QString x = result; FrameLoaderClientQt *fl = static_cast<FrameLoaderClientQt*>(f->loader()->client()); bool rc = m_webPage->javaScriptPrompt(fl->webFrame(), (QString)message, (QString)defaultValue, &x); - result = x; + + // Fix up a quirk in the QInputDialog class. If no input happened the string should be empty + // but it is null. See https://bugs.webkit.org/show_bug.cgi?id=30914. + if (rc && result.isNull()) + result = String(""); + else + result = x; + return rc; } diff --git a/src/s60installs/bwins/QtWebKitu.def b/src/3rdparty/webkit/WebKit/qt/symbian/bwins/QtWebKitu.def index e5631f8..e5631f8 100644 --- a/src/s60installs/bwins/QtWebKitu.def +++ b/src/3rdparty/webkit/WebKit/qt/symbian/bwins/QtWebKitu.def diff --git a/src/s60installs/eabi/QtWebKitu.def b/src/3rdparty/webkit/WebKit/qt/symbian/eabi/QtWebKitu.def index 4aad884..4aad884 100644 --- a/src/s60installs/eabi/QtWebKitu.def +++ b/src/3rdparty/webkit/WebKit/qt/symbian/eabi/QtWebKitu.def diff --git a/src/activeqt/container/qaxbase.cpp b/src/activeqt/container/qaxbase.cpp index 3795f56..ed7ac29 100644 --- a/src/activeqt/container/qaxbase.cpp +++ b/src/activeqt/container/qaxbase.cpp @@ -909,7 +909,7 @@ QAxMetaObject *QAxBase::internalMetaObject() const \property QAxBase::control \brief the name of the COM object wrapped by this QAxBase object. - Setting this property initilializes the COM object. Any COM object + Setting this property initializes the COM object. Any COM object previously set is shut down. The most efficient way to set this property is by using the diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp index d529f67..bc0d35e 100644 --- a/src/corelib/animation/qvariantanimation.cpp +++ b/src/corelib/animation/qvariantanimation.cpp @@ -373,6 +373,13 @@ QVariantAnimation::~QVariantAnimation() Another example is QEasingCurve::InOutElastic, which provides an elastic effect on the values of the interpolated variant. + QVariantAnimation will use the QEasingCurve::valueForProgress() to + transform the "normalized progress" (currentTime / totalDuration) + of the animation into the effective progress actually + used by the animation. It is this effective progress that will be + the progress when interpolated() is called. Also, the steps in the + keyValues are referring to this effective progress. + The easing curve is used with the interpolator, the interpolated() virtual function, the animation's duration, and iterationCount, to control how the current value changes as the animation progresses. diff --git a/src/corelib/concurrent/qtconcurrentiteratekernel.cpp b/src/corelib/concurrent/qtconcurrentiteratekernel.cpp index 15b8ecd..e93394f 100644 --- a/src/corelib/concurrent/qtconcurrentiteratekernel.cpp +++ b/src/corelib/concurrent/qtconcurrentiteratekernel.cpp @@ -46,6 +46,9 @@ #include <mach/mach_time.h> #include <unistd.h> #elif defined(Q_OS_UNIX) +#if defined(Q_OS_HURD) +#include <sys/time.h> +#endif #include <time.h> #include <unistd.h> #elif defined(Q_OS_WIN) diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 62b5409..dfe610c 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -77,6 +77,7 @@ #include <e32def.h> #include <e32debug.h> #include <f32file.h> +#include <e32math.h> # include "private/qcore_symbian_p.h" _LIT(qt_S60Filter, "Series60v?.*.sis"); @@ -1225,7 +1226,7 @@ bool qSharedBuild() Defined on Mac OS X. - \sa Q_WS_WIN, Q_WS_X11, Q_WS_QWS + \sa Q_WS_WIN, Q_WS_X11, Q_WS_QWS, Q_WS_S60 */ /*! @@ -1234,7 +1235,7 @@ bool qSharedBuild() Defined on Windows. - \sa Q_WS_MAC, Q_WS_X11, Q_WS_QWS + \sa Q_WS_MAC, Q_WS_X11, Q_WS_QWS, Q_WS_S60 */ /*! @@ -1243,7 +1244,7 @@ bool qSharedBuild() Defined on X11. - \sa Q_WS_MAC, Q_WS_WIN, Q_WS_QWS + \sa Q_WS_MAC, Q_WS_WIN, Q_WS_QWS, Q_WS_S60 */ /*! @@ -1252,7 +1253,7 @@ bool qSharedBuild() Defined on Qt for Embedded Linux. - \sa Q_WS_MAC, Q_WS_WIN, Q_WS_X11 + \sa Q_WS_MAC, Q_WS_WIN, Q_WS_X11, Q_WS_S60 */ /*! @@ -1598,6 +1599,29 @@ bool qSharedBuild() Optimizing C++ Compilers. */ +/*! + \macro Q_OS_MAC + \relates <QtGlobal> + + Defined on MAC OS (synonym for Darwin). + */ + +/*! + \macro Q_OS_SYMBIAN + \relates <QtGlobal> + + Defined on Symbian. + */ + +/*! + \macro Q_WS_S60 + \relates <QtGlobal> + + Defined on S60. + + \sa Q_WS_MAC, Q_WS_WIN, Q_WS_X11, Q_WS_QWS + */ + #if defined(QT_BUILD_QMAKE) // needed to bootstrap qmake static const unsigned int qt_one = 1; @@ -2493,7 +2517,7 @@ bool qputenv(const char *varName, const QByteArray& value) #endif } -#if (defined(Q_OS_UNIX) || defined(Q_OS_WIN)) && !defined(QT_NO_THREAD) && !defined(Q_OS_SYMBIAN) +#if (defined(Q_OS_UNIX) || defined(Q_OS_WIN)) && !defined(QT_NO_THREAD) # if defined(Q_OS_INTEGRITY) && defined(__GHS_VERSION_NUMBER) && (__GHS_VERSION_NUMBER < 500) // older versions of INTEGRITY used a long instead of a uint for the seed. @@ -2516,8 +2540,6 @@ Q_GLOBAL_STATIC(SeedStorage, randTLS) // Thread Local Storage for seed value Sets the argument \a seed to be used to generate a new random number sequence of pseudo random integers to be returned by qrand(). - If no seed value is provided, qrand() is automatically seeded with a value of 1. - The sequence of random numbers generated is deterministic per thread. For example, if two threads call qsrand(1) and subsequently calls qrand(), the threads will get the same random number sequence. @@ -2541,8 +2563,9 @@ void qsrand(uint seed) srand(seed); } #else - // On Windows srand() and rand() already use Thread-Local-Storage + // On Windows and Symbian srand() and rand() already use Thread-Local-Storage // to store the seed between calls + // this is also valid for QT_NO_THREAD srand(seed); #endif } @@ -2558,7 +2581,7 @@ void qsrand(uint seed) */ void qsrand() { -#if (defined(Q_OS_UNIX) || defined(Q_OS_WIN)) && !defined(QT_NO_THREAD) && !defined(Q_OS_SYMBIAN) +#if (defined(Q_OS_UNIX) || defined(Q_OS_WIN)) && !defined(QT_NO_THREAD) SeedStorage *seedStorage = randTLS(); if (seedStorage) { SeedStorageType *pseed = seedStorage->localData(); @@ -2572,24 +2595,28 @@ void qsrand() *pseed = QDateTime::currentDateTime().toTime_t() + quintptr(&pseed) + serial.fetchAndAddRelaxed(1); -#if defined(Q_OS_WIN) - // for Windows the srand function must still be called. +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) + // for Windows and Symbian the srand function must still be called. srand(*pseed); #endif } -#elif defined(Q_OS_WIN) +//QT_NO_THREAD implementations +#else static unsigned int seed = 0; if (seed) return; +#if defined(Q_OS_SYMBIAN) + seed = Math::Random(); +#elif defined(Q_OS_WIN) seed = GetTickCount(); - srand(seed); #else - // Symbian? - -#endif // defined(Q_OS_UNIX) || defined(Q_OS_WIN)) && !defined(QT_NO_THREAD) && !defined(Q_OS_SYMBIAN) + seed = quintptr(&seed) + QDateTime::currentDateTime().toTime_t(); +#endif + srand(seed); +#endif // defined(Q_OS_UNIX) || defined(Q_OS_WIN)) && !defined(QT_NO_THREAD) } /*! @@ -2626,8 +2653,9 @@ int qrand() return rand(); } #else - // On Windows srand() and rand() already use Thread-Local-Storage + // On Windows and Symbian srand() and rand() already use Thread-Local-Storage // to store the seed between calls + // this is also valid for QT_NO_THREAD return rand(); #endif } diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h index ff8c6c8..c1c7812 100644 --- a/src/corelib/io/qdebug.h +++ b/src/corelib/io/qdebug.h @@ -93,7 +93,7 @@ public: inline QDebug &maybeSpace() { if (stream->space) stream->ts << ' '; return *this; } inline QDebug &operator<<(QChar t) { stream->ts << '\'' << t << '\''; return maybeSpace(); } - inline QDebug &operator<<(QBool t) { stream->ts << (bool(t) ? "true" : "false"); return maybeSpace(); } + inline QDebug &operator<<(QBool t) { stream->ts << (bool(t != 0) ? "true" : "false"); return maybeSpace(); } inline QDebug &operator<<(bool t) { stream->ts << (t ? "true" : "false"); return maybeSpace(); } inline QDebug &operator<<(char t) { stream->ts << t; return maybeSpace(); } inline QDebug &operator<<(signed short t) { stream->ts << t; return maybeSpace(); } diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 59db9a6..bac508a 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -1125,10 +1125,11 @@ QDir::Filters QDir::filter() const execute access. The Executable value needs to be combined with Dirs or Files. \value Modified Only list files that have been modified (ignored - under Unix). - \value Hidden List hidden files (on Unix, files starting with a .). + on Unix). + \value Hidden List hidden files (on Unix, files starting with a "."). \value System List system files (on Unix, FIFOs, sockets and - device files) + device files are included; on Windows, \c {.lnk} + files are included) \value CaseSensitive The filter should be case sensitive. \omitvalue DefaultFilter diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 61081a1..0a435b9 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -573,6 +573,8 @@ QString QFileInfo::canonicalFilePath() const QString QFileInfo::absolutePath() const { Q_D(const QFileInfo); + if (d->data->fileName.isEmpty()) + qWarning("QFileInfo::absolutePath: Constructed with empty filename"); if(!d->data->fileEngine) return QLatin1String(""); return d->getFileName(QAbstractFileEngine::AbsolutePathName); diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index e4c4e3f..c064d5a 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -144,7 +144,7 @@ QString QFSFileEnginePrivate::canonicalized(const QString &path) return path; #endif // Mac OS X 10.5.x doesn't support the realpath(X,0) extenstion we use here. -#if defined(Q_OS_LINIX) || defined(Q_OS_SYMBIAN) +#if defined(Q_OS_LINUX) || defined(Q_OS_SYMBIAN) char *ret = realpath(path.toLocal8Bit().constData(), (char*)0); if (ret) { QString canonicalPath = QDir::cleanPath(QString::fromLocal8Bit(ret)); diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 71414ce..ea262bf 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -825,10 +825,9 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const ret |= RootFlag; } else { QString baseName = fileName(BaseName); - if ((baseName.size() > 1 - && baseName.at(0) == QLatin1Char('.') && baseName.at(1) != QLatin1Char('.')) + if ((baseName.size() > 0 && baseName.at(0) == QLatin1Char('.')) # if !defined(QWS) && defined(Q_OS_MAC) - || _q_isMacHidden(d->filePath) + || _q_isMacHidden(d->filePath) # endif ) { ret |= HiddenFlag; diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index a6cb5a9..a7719a8 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -1595,13 +1595,10 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(QAbstractFileEngine::Fil ret |= LocalDiskFlag; if (d->doStat()) { ret |= ExistsFlag; - if (d->filePath == QLatin1String("/") || isDriveRoot(d->filePath) || isUncRoot(d->filePath)) { + if (d->filePath == QLatin1String("/") || isDriveRoot(d->filePath) || isUncRoot(d->filePath)) ret |= RootFlag; - } else if (d->fileAttrib & FILE_ATTRIBUTE_HIDDEN) { - QString baseName = fileName(BaseName); - if (baseName != QLatin1String(".") && baseName != QLatin1String("..")) - ret |= HiddenFlag; - } + else if (d->fileAttrib & FILE_ATTRIBUTE_HIDDEN) + ret |= HiddenFlag; } } return ret; diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index 0e5a2de..8dcccb4 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -965,7 +965,15 @@ QByteArray QIODevice::readAll() QByteArray result; qint64 readBytes = 0; - if (d->isSequential() || (readBytes = size()) == 0) { + + // flush internal read buffer + if (!(d->openMode & Text) && !d->buffer.isEmpty()) { + result = d->buffer.readAll(); + readBytes = result.size(); + } + + qint64 theSize; + if (d->isSequential() || (theSize = size()) == 0) { // Size is unknown, read incrementally. qint64 readResult; do { @@ -977,7 +985,7 @@ QByteArray QIODevice::readAll() } else { // Read it all in one go. // If resize fails, don't read anything. - result.resize(int(readBytes - d->pos)); + result.resize(int(theSize - d->pos)); readBytes = read(result.data(), result.size()); } diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index 5c543d4..a061ad1 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -273,7 +273,7 @@ QResourcePrivate::load(const QString &file) QString cleaned = cleanPath(file); for(int i = 0; i < list->size(); ++i) { QResourceRoot *res = list->at(i); - const int node = res->findNode(cleaned); + const int node = res->findNode(cleaned, locale); if(node != -1) { if(related.isEmpty()) { container = res->isContainer(node); diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 594718e..47f340c 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -440,7 +440,7 @@ QTextStreamPrivate::QTextStreamPrivate(QTextStream *q_ptr) readConverterSavedState(0), #endif readConverterSavedStateOffset(0), - locale(QLocale::C) + locale(QLocale::c()) { this->q_ptr = q_ptr; reset(); @@ -1806,8 +1806,7 @@ QTextStreamPrivate::NumberParsingStatus QTextStreamPrivate::getNumber(qulonglong if (ch.isDigit()) { val *= 10; val += ch.digitValue(); - } else if (locale.language() != QLocale::C - && ch == locale.groupSeparator()) { + } else if (locale != QLocale::c() && ch == locale.groupSeparator()) { continue; } else { ungetChar(ch); @@ -1958,7 +1957,7 @@ bool QTextStreamPrivate::getReal(double *f) else if (lc == locale.negativeSign().toLower() || lc == locale.positiveSign().toLower()) input = InputSign; - else if (locale.language() != QLocale::C // backward-compatibility + else if (locale != QLocale::c() // backward-compatibility && lc == locale.groupSeparator().toLower()) input = InputDigit; // well, it isn't a digit, but no one cares. else @@ -2283,7 +2282,7 @@ bool QTextStreamPrivate::putNumber(qulonglong number, bool negative) // add thousands group separators. For backward compatibility we // don't add a group separator for C locale. - if (locale.language() != QLocale::C) + if (locale != QLocale::c()) flags |= QLocalePrivate::ThousandsGroup; const QLocalePrivate *dd = locale.d(); diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index fd51bcf..6ac6468 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -3864,14 +3864,18 @@ QByteArray QUrlPrivate::toEncoded(QUrl::FormattingOptions options) const url += "//"; if ((options & QUrl::RemoveUserInfo) != QUrl::RemoveUserInfo) { + bool hasUserOrPass = false; if (!userName.isEmpty()) { url += encodedUserName; - if (!(options & QUrl::RemovePassword) && !password.isEmpty()) { - url += ':'; - url += encodedPassword; - } - url += '@'; + hasUserOrPass = true; } + if (!(options & QUrl::RemovePassword) && !password.isEmpty()) { + url += ':'; + url += encodedPassword; + hasUserOrPass = true; + } + if (hasUserOrPass) + url += '@'; } if (host.startsWith(QLatin1Char('['))) { diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp index 665b73e..16871c3 100644 --- a/src/corelib/kernel/qeventdispatcher_glib.cpp +++ b/src/corelib/kernel/qeventdispatcher_glib.cpp @@ -341,6 +341,11 @@ QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate(GMainContext *context) g_source_attach(&idleTimerSource->source, mainContext); } +void QEventDispatcherGlibPrivate::runTimersOnceWithNormalPriority() +{ + timerSource->runWithIdlePriority = false; +} + QEventDispatcherGlib::QEventDispatcherGlib(QObject *parent) : QAbstractEventDispatcher(*(new QEventDispatcherGlibPrivate), parent) { diff --git a/src/corelib/kernel/qeventdispatcher_glib_p.h b/src/corelib/kernel/qeventdispatcher_glib_p.h index 6a4e726..57cbf94 100644 --- a/src/corelib/kernel/qeventdispatcher_glib_p.h +++ b/src/corelib/kernel/qeventdispatcher_glib_p.h @@ -110,6 +110,8 @@ public: GSocketNotifierSource *socketNotifierSource; GTimerSource *timerSource; GIdleTimerSource *idleTimerSource; + + void runTimersOnceWithNormalPriority(); }; QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmath.h b/src/corelib/kernel/qmath.h index 820f424..16e6bb7 100644 --- a/src/corelib/kernel/qmath.h +++ b/src/corelib/kernel/qmath.h @@ -46,6 +46,10 @@ #include <QtCore/qglobal.h> +#ifdef Q_OS_SYMBIAN +# include <e32math.h> +#endif + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -88,82 +92,130 @@ inline qreal qFabs(qreal v) inline qreal qSin(qreal v) { -#ifdef QT_USE_MATH_H_FLOATS - if (sizeof(qreal) == sizeof(float)) - return sinf(float(v)); - else +#ifdef Q_OS_SYMBIAN + TReal sin_v; + Math::Sin(sin_v, static_cast<TReal>(v)); + return static_cast<qreal>(sin_v); +#else +# ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return sinf(float(v)); + else +# endif + return sin(v); #endif - return sin(v); } inline qreal qCos(qreal v) { -#ifdef QT_USE_MATH_H_FLOATS - if (sizeof(qreal) == sizeof(float)) - return cosf(float(v)); - else +#ifdef Q_OS_SYMBIAN + TReal cos_v; + Math::Cos(cos_v, static_cast<TReal>(v)); + return static_cast<qreal>(cos_v); +#else +# ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return cosf(float(v)); + else +# endif + return cos(v); #endif - return cos(v); } inline qreal qTan(qreal v) { -#ifdef QT_USE_MATH_H_FLOATS - if (sizeof(qreal) == sizeof(float)) - return tanf(float(v)); - else +#ifdef Q_OS_SYMBIAN + TReal tan_v; + Math::Tan(tan_v, static_cast<TReal>(v)); + return static_cast<qreal>(tan_v); +#else +# ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return tanf(float(v)); + else +# endif + return tan(v); #endif - return tan(v); } inline qreal qAcos(qreal v) { -#ifdef QT_USE_MATH_H_FLOATS - if (sizeof(qreal) == sizeof(float)) - return acosf(float(v)); - else +#ifdef Q_OS_SYMBIAN + TReal acos_v; + Math::ACos(acos_v, static_cast<TReal>(v)); + return static_cast<qreal>(acos_v); +#else +# ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return acosf(float(v)); + else +# endif + return acos(v); #endif - return acos(v); } inline qreal qAsin(qreal v) { -#ifdef QT_USE_MATH_H_FLOATS - if (sizeof(qreal) == sizeof(float)) - return asinf(float(v)); - else +#ifdef Q_OS_SYMBIAN + TReal asin_v; + Math::ASin(asin_v, static_cast<TReal>(v)); + return static_cast<qreal>(asin_v); +#else +# ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return asinf(float(v)); + else +# endif + return asin(v); #endif - return asin(v); } inline qreal qAtan(qreal v) { -#ifdef QT_USE_MATH_H_FLOATS - if(sizeof(qreal) == sizeof(float)) - return atanf(float(v)); - else +#ifdef Q_OS_SYMBIAN + TReal atan_v; + Math::ATan(atan_v, static_cast<TReal>(v)); + return static_cast<qreal>(atan_v); +#else +# ifdef QT_USE_MATH_H_FLOATS + if(sizeof(qreal) == sizeof(float)) + return atanf(float(v)); + else +# endif + return atan(v); #endif - return atan(v); } inline qreal qAtan2(qreal x, qreal y) { -#ifdef QT_USE_MATH_H_FLOATS - if(sizeof(qreal) == sizeof(float)) - return atan2f(float(x), float(y)); - else +#ifdef Q_OS_SYMBIAN + TReal atan2_v; + Math::ATan(atan2_v, static_cast<TReal>(x), static_cast<TReal>(y)); + return static_cast<qreal>(atan2_v); +#else +# ifdef QT_USE_MATH_H_FLOATS + if(sizeof(qreal) == sizeof(float)) + return atan2f(float(x), float(y)); + else +# endif + return atan2(x, y); #endif - return atan2(x, y); } inline qreal qSqrt(qreal v) { -#ifdef QT_USE_MATH_H_FLOATS - if (sizeof(qreal) == sizeof(float)) - return sqrtf(float(v)); - else +#ifdef Q_OS_SYMBIAN + TReal sqrt_v; + Math::Sqrt(sqrt_v, static_cast<TReal>(v)); + return static_cast<qreal>(sqrt_v); +#else +# ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return sqrtf(float(v)); + else +# endif + return sqrt(v); #endif - return sqrt(v); } inline qreal qLn(qreal v) @@ -178,19 +230,31 @@ inline qreal qLn(qreal v) inline qreal qExp(qreal v) { +#ifdef Q_OS_SYMBIAN + TReal exp_v; + Math::Exp(exp_v, static_cast<TReal>(v)); + return static_cast<qreal>(exp_v); +#else // only one signature // exists, exp(double) return exp(v); +#endif } inline qreal qPow(qreal x, qreal y) { -#ifdef QT_USE_MATH_H_FLOATS - if (sizeof(qreal) == sizeof(float)) - return powf(float(x), float(y)); - else +#ifdef Q_OS_SYMBIAN + TReal pow_v; + Math::Pow(pow_v, static_cast<TReal>(x), static_cast<TReal>(y)); + return static_cast<qreal>(pow_v); +#else +# ifdef QT_USE_MATH_H_FLOATS + if (sizeof(qreal) == sizeof(float)) + return powf(float(x), float(y)); + else +# endif + return pow(x, y); #endif - return pow(x, y); } #ifndef M_PI diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 6e6da19..72d6786 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -2648,6 +2648,7 @@ const char* QMetaClassInfo::value() const */ int QMetaObjectPrivate::originalClone(const QMetaObject *mobj, int local_method_index) { + Q_ASSERT(local_method_index < get(mobj)->methodCount); int handle = get(mobj)->methodData + 5 * local_method_index; while (mobj->d.data[handle + 4] & MethodCloned) { Q_ASSERT(local_method_index > 0); diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 30cd011..305ec4f 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -145,7 +145,7 @@ QObjectPrivate::QObjectPrivate(int version) receiveChildEvents = true; postedEvents = 0; extraData = 0; - connectedSignals = 0; + connectedSignals[0] = connectedSignals[1] = 0; inEventHandler = false; inThreadChangeEvent = false; deleteWatch = 0; @@ -578,12 +578,13 @@ int QMetaCallEvent::placeMetaCall(QObject *object) protected functions connectNotify() and disconnectNotify() make it possible to track connections. - QObjects organize themselves in object trees. When you create a - QObject with another object as parent, the object will - automatically add itself to the parent's children() list. The - parent takes ownership of the object; i.e., it will automatically - delete its children in its destructor. You can look for an object - by name and optionally type using findChild() or findChildren(). + QObjects organize themselves in \l {Object Trees and Object + Ownership} {object trees}. When you create a QObject with another + object as parent, the object will automatically add itself to the + parent's children() list. The parent takes ownership of the + object; i.e., it will automatically delete its children in its + destructor. You can look for an object by name and optionally type + using findChild() or findChildren(). Every object has an objectName() and its class name can be found via the corresponding metaObject() (see QMetaObject::className()). @@ -682,7 +683,7 @@ int QMetaCallEvent::placeMetaCall(QObject *object) \l{Writing Source Code for Translation} document. \sa QMetaObject, QPointer, QObjectCleanupHandler, Q_DISABLE_COPY() - {Object Trees and Object Ownership} + \sa {Object Trees and Object Ownership} */ /*! @@ -2850,6 +2851,27 @@ void QObject::disconnectNotify(const char *) { } +/* \internal + convert a signal index from the method range to the signal range + */ +static int methodIndexToSignalIndex(const QMetaObject *metaObject, int signal_index) +{ + if (signal_index < 0) + return signal_index; + while (metaObject && metaObject->methodOffset() > signal_index) + metaObject = metaObject->superClass(); + + if (metaObject) { + int signalOffset, methodOffset; + computeOffsets(metaObject, &signalOffset, &methodOffset); + if (signal_index < metaObject->methodCount()) + signal_index = QMetaObjectPrivate::originalClone(metaObject, signal_index - methodOffset) + signalOffset; + else + signal_index = signal_index - methodOffset + signalOffset; + } + return signal_index; +} + /*!\internal \a types is a 0-terminated vector of meta types for queued connections. @@ -2860,16 +2882,7 @@ void QObject::disconnectNotify(const char *) bool QMetaObject::connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type, int *types) { - if (signal_index > 0) { - const QMetaObject *mo = sender->metaObject(); - while (mo && mo->methodOffset() > signal_index) - mo = mo->superClass(); - if (mo) { - int signalOffset, methodOffset; - computeOffsets(mo, &signalOffset, &methodOffset); - signal_index = QMetaObjectPrivate::originalClone(mo, signal_index - methodOffset) + signalOffset; - } - } + signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index); return QMetaObjectPrivate::connect(sender, signal_index, receiver, method_index, type, types); } @@ -2924,9 +2937,9 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index, QObjectPrivate *const sender_d = QObjectPrivate::get(s); if (signal_index < 0) { - sender_d->connectedSignals = ~ulong(0); + sender_d->connectedSignals[0] = sender_d->connectedSignals[1] = ~0; } else if (signal_index < (int)sizeof(sender_d->connectedSignals) * 8) { - sender_d->connectedSignals |= ulong(1) << signal_index; + sender_d->connectedSignals[signal_index >> 5] |= (1 << (signal_index & 0x1f)); } return true; @@ -2938,16 +2951,7 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index, bool QMetaObject::disconnect(const QObject *sender, int signal_index, const QObject *receiver, int method_index) { - if (signal_index > 0) { - const QMetaObject *mo = sender->metaObject(); - while (mo && mo->methodOffset() > signal_index) - mo = mo->superClass(); - if (mo) { - int signalOffset, methodOffset; - computeOffsets(mo, &signalOffset, &methodOffset); - signal_index = QMetaObjectPrivate::originalClone(mo, signal_index - methodOffset) + signalOffset; - } - } + signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index); return QMetaObjectPrivate::disconnect(sender, signal_index, receiver, method_index); } diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index f899c78..d1841be 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -172,7 +172,7 @@ public: } int signalIndex(const char *signalName) const; - inline bool isSignalConnected(int signalIdx) const; + inline bool isSignalConnected(uint signalIdx) const; public: QString objectName; @@ -183,7 +183,7 @@ public: Connection *senders; // linked list of connections connected to this object Sender *currentSender; // object currently activating the object - mutable ulong connectedSignals; + mutable quint32 connectedSignals[2]; #ifdef QT3_SUPPORT QList<QObject *> pendingChildInsertedEvents; @@ -205,6 +205,7 @@ public: int *deleteWatch; }; + /*! \internal Returns true if the signal with index \a signal_index from object \a sender is connected. @@ -213,12 +214,12 @@ public: \a signal_index must be the index returned by QObjectPrivate::signalIndex; */ -inline bool QObjectPrivate::isSignalConnected(int signal_index) const +inline bool QObjectPrivate::isSignalConnected(uint signal_index) const { - return signal_index >= (int)sizeof(connectedSignals) * 8 + return signal_index >= sizeof(connectedSignals) * 8 || qt_signal_spy_callback_set.signal_begin_callback || qt_signal_spy_callback_set.signal_end_callback - || (connectedSignals & (ulong(1) << signal_index)); + || (connectedSignals[signal_index >> 5] & (1 << (signal_index & 0x1f))); } diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 3c10788..74ff17f 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -458,7 +458,7 @@ inline void qVariantSetValue(QVariant &v, const T &t) //if possible we reuse the current QVariant private const uint type = qMetaTypeId<T>(reinterpret_cast<T *>(0)); QVariant::Private &d = v.data_ptr(); - if (v.isDetached() && (type <= uint(QVariant::Char) || type == d.type)) { + if (v.isDetached() && (type == d.type || (type <= uint(QVariant::Char) && d.type <= uint(QVariant::Char)))) { d.type = type; d.is_null = false; T *old = reinterpret_cast<T*>(d.is_shared ? d.data.shared->ptr : &d.data.ptr); diff --git a/src/corelib/statemachine/qsignaltransition.cpp b/src/corelib/statemachine/qsignaltransition.cpp index f55f634..d35c12e 100644 --- a/src/corelib/statemachine/qsignaltransition.cpp +++ b/src/corelib/statemachine/qsignaltransition.cpp @@ -76,7 +76,7 @@ QT_BEGIN_NAMESPACE CheckedTransition(QCheckBox *check) : QSignalTransition(check, SIGNAL(stateChanged(int))) {} protected: - bool eventTest(QEvent *e) const { + bool eventTest(QEvent *e) { if (!QSignalTransition::eventTest(e)) return false; QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(e); diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index af68434..3db308f 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -202,7 +202,7 @@ public: QStack<QEventLoop *> eventLoops; QPostEventList postEventList; bool canWait; - QMap<int, void *> tls; + QVector<void *> tls; QMutex mutex; diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 21b5e65..0309c67 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -74,6 +74,10 @@ # endif #endif +#ifdef Q_OS_HPUX +#include <sys/pstat.h> +#endif + #if defined(Q_OS_MAC) # ifdef qDebug # define old_qDebug qDebug diff --git a/src/corelib/thread/qthreadstorage.cpp b/src/corelib/thread/qthreadstorage.cpp index 8b1f255..a7d53d0 100644 --- a/src/corelib/thread/qthreadstorage.cpp +++ b/src/corelib/thread/qthreadstorage.cpp @@ -71,27 +71,32 @@ void qtsDebug(const char *fmt, ...) # define DEBUG_MSG if(false)qDebug #endif -static QBasicAtomicInt idCounter = Q_BASIC_ATOMIC_INITIALIZER(INT_MAX); Q_GLOBAL_STATIC(QMutex, mutex) -typedef QMap<int, void (*)(void *)> DestructorMap; +typedef QVector<void (*)(void *)> DestructorMap; Q_GLOBAL_STATIC(DestructorMap, destructors) QThreadStorageData::QThreadStorageData(void (*func)(void *)) - : id(idCounter.fetchAndAddRelaxed(-1)) { QMutexLocker locker(mutex()); - destructors()->insert(id, func); - + DestructorMap *destr = destructors(); + for (id = 0; id < destr->count(); id++) { + if (destr->at(id) == 0) + break; + } + if (id == destr->count()) { + destr->append(func); + } else { + (*destr)[id] = func; + } DEBUG_MSG("QThreadStorageData: Allocated id %d, destructor %p", id, func); } QThreadStorageData::~QThreadStorageData() { + DEBUG_MSG("QThreadStorageData: Released id %d", id); QMutexLocker locker(mutex()); if (destructors()) - destructors()->remove(id); - - DEBUG_MSG("QThreadStorageData: Released id %d", id); + (*destructors())[id] = 0; } void **QThreadStorageData::get() const @@ -101,14 +106,17 @@ void **QThreadStorageData::get() const qWarning("QThreadStorage::get: QThreadStorage can only be used with threads started with QThread"); return 0; } - QMap<int, void *>::const_iterator it = data->tls.constFind(id); + QVector<void *> &tls = data->tls; + if (tls.size() <= id) + tls.resize(id + 1); + void **v = &tls[id]; + DEBUG_MSG("QThreadStorageData: Returning storage %d, data %p, for thread %p", id, - it != data->tls.end() ? it.value() : 0, + *v, data->thread); - // const_cast below is a bit evil - but we have to make sure not to detach here - // otherwise we'll go bonkers in oom situations - return it != data->tls.constEnd() && it.value() != 0 ? const_cast<void **>(&it.value()) : 0; + + return *v ? v : 0; } void **QThreadStorageData::set(void *p) @@ -118,51 +126,46 @@ void **QThreadStorageData::set(void *p) qWarning("QThreadStorage::set: QThreadStorage can only be used with threads started with QThread"); return 0; } + QVector<void *> &tls = data->tls; + if (tls.size() <= id) + tls.resize(id + 1); + + void *&value = tls[id]; + // delete any previous data + if (value != 0) { + DEBUG_MSG("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p", + id, + value, + data->thread); - QMap<int, void *>::iterator it = data->tls.find(id); - if (it != data->tls.end()) { - // delete any previous data - if (it.value() != 0) { - DEBUG_MSG("QThreadStorageData: Deleting previous storage %d, data %p, for thread %p", - id, - it.value(), - data->thread); - - void *q = it.value(); - it.value() = 0; - - QMutexLocker locker(mutex()); - void (*destructor)(void *) = destructors()->value(id); - locker.unlock(); + QMutexLocker locker(mutex()); + void (*destructor)(void *) = destructors()->value(id); + locker.unlock(); - destructor(q); - } + void *q = value; + value = 0; - // store new data - it.value() = p; - DEBUG_MSG("QThreadStorageData: Set storage %d for thread %p to %p", id, data->thread, p); - } else { - it = data->tls.insert(id, p); - DEBUG_MSG("QThreadStorageData: Inserted storage %d, data %p, for thread %p", id, p, data->thread); + destructor(q); } - return &it.value(); + // store new data + value = p; + DEBUG_MSG("QThreadStorageData: Set storage %d for thread %p to %p", id, data->thread, p); + return &value; } void QThreadStorageData::finish(void **p) { - QMap<int, void *> *tls = reinterpret_cast<QMap<int, void *> *>(p); + QVector<void *> *tls = reinterpret_cast<QVector<void *> *>(p); if (!tls || tls->isEmpty() || !mutex()) return; // nothing to do DEBUG_MSG("QThreadStorageData: Destroying storage for thread %p", QThread::currentThread()); - QMap<int, void *>::iterator it = tls->begin(); - while (it != tls->end()) { - int id = it.key(); - void *q = it.value(); - it.value() = 0; - ++it; + for(int i = tls->size() - 1; i >= 0; i--) { + void *&value = (*tls)[i]; + void *q = value; + value = 0; if (!q) { // data already deleted @@ -170,16 +173,16 @@ void QThreadStorageData::finish(void **p) } QMutexLocker locker(mutex()); - void (*destructor)(void *) = destructors()->value(id); + void (*destructor)(void *) = destructors()->value(i); locker.unlock(); if (!destructor) { if (QThread::currentThread()) qWarning("QThreadStorage: Thread %p exited after QThreadStorage %d destroyed", - QThread::currentThread(), id); + QThread::currentThread(), i); continue; } - destructor(q); + destructor(q); //crash here might mean the thread exited after qthreadstorage was destroyed } tls->clear(); } diff --git a/src/corelib/tools/qcache.h b/src/corelib/tools/qcache.h index 46e20b1..66f9f73 100644 --- a/src/corelib/tools/qcache.h +++ b/src/corelib/tools/qcache.h @@ -70,8 +70,9 @@ class QCache if (l == &n) l = n.p; if (f == &n) f = n.n; total -= n.c; - delete n.t; + T *obj = n.t; hash.remove(*n.keyPtr); + delete obj; } inline T *relink(const Key &key) { typename QHash<Key, Node>::iterator i = hash.find(key); diff --git a/src/corelib/tools/qline.cpp b/src/corelib/tools/qline.cpp index d0afb7a..8112757 100644 --- a/src/corelib/tools/qline.cpp +++ b/src/corelib/tools/qline.cpp @@ -574,7 +574,7 @@ qreal QLineF::angle() const const qreal dx = pt2.x() - pt1.x(); const qreal dy = pt2.y() - pt1.y(); - const qreal theta = atan2(-dy, dx) * 360.0 / M_2PI; + const qreal theta = qAtan2(-dy, dx) * 360.0 / M_2PI; const qreal theta_normalized = theta < 0 ? theta + 360 : theta; @@ -814,7 +814,7 @@ qreal QLineF::angle(const QLineF &l) const qreal cos_line = (dx()*l.dx() + dy()*l.dy()) / (length()*l.length()); qreal rad = 0; // only accept cos_line in the range [-1,1], if it is outside, use 0 (we return 0 rather than PI for those cases) - if (cos_line >= -1.0 && cos_line <= 1.0) rad = acos( cos_line ); + if (cos_line >= -1.0 && cos_line <= 1.0) rad = qAcos( cos_line ); return rad * 360 / M_2PI; } diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 4a66b92..8645f17 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -1187,14 +1187,14 @@ QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const } case DateFormatLong: case DateFormatShort: - return macToQtFormat(getMacDateFormat(type == DateFormatShort + return getMacDateFormat(type == DateFormatShort ? kCFDateFormatterShortStyle - : kCFDateFormatterLongStyle)); + : kCFDateFormatterLongStyle); case TimeFormatLong: case TimeFormatShort: - return macToQtFormat(getMacTimeFormat(type == TimeFormatShort + return getMacTimeFormat(type == TimeFormatShort ? kCFDateFormatterShortStyle - : kCFDateFormatterLongStyle)); + : kCFDateFormatterLongStyle); case DayNameLong: case DayNameShort: return macDayName(in.toInt(), (type == DayNameShort)); diff --git a/src/corelib/tools/qregexp.h b/src/corelib/tools/qregexp.h index 2bad40e..8a46b98 100644 --- a/src/corelib/tools/qregexp.h +++ b/src/corelib/tools/qregexp.h @@ -119,7 +119,9 @@ public: #endif int matchedLength() const; #ifndef QT_NO_REGEXP_CAPTURE +#ifdef QT_DEPRECATED QT_DEPRECATED int numCaptures() const; +#endif int captureCount() const; QStringList capturedTexts() const; QStringList capturedTexts(); diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp index 994da10..ff0a93e 100644 --- a/src/dbus/qdbusabstractinterface.cpp +++ b/src/dbus/qdbusabstractinterface.cpp @@ -561,13 +561,7 @@ void QDBusAbstractInterface::connectNotify(const char *signal) QDBusConnectionPrivate *conn = d->connectionPrivate(); if (conn) { - // do we know what our owner is? - QString owner; - if (!d->service.isEmpty() && d->currentOwner.isNull()) - owner = QLatin1String(""); - else - owner = d->currentOwner; - conn->connectRelay(d->service, owner, d->path, d->interface, + conn->connectRelay(d->service, d->path, d->interface, this, signal); } } @@ -585,7 +579,7 @@ void QDBusAbstractInterface::disconnectNotify(const char *signal) QDBusConnectionPrivate *conn = d->connectionPrivate(); if (conn) - conn->disconnectRelay(d->service, d->currentOwner, d->path, d->interface, + conn->disconnectRelay(d->service, d->path, d->interface, this, signal); } diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index d7088ff..47893cc 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -619,10 +619,8 @@ bool QDBusConnection::connect(const QString &service, const QString &path, const if (interface.isEmpty() && name.isEmpty()) return false; - QString owner = d->getNameOwner(service); // we don't care if the owner is empty - // it might get started later QDBusWriteLocker locker(ConnectAction, d); - return d->connectSignal(service, owner, path, interface, name, argumentMatch, signature, receiver, slot); + return d->connectSignal(service, path, interface, name, argumentMatch, signature, receiver, slot); } /*! diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index d6f7598..32e057c 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -119,7 +119,7 @@ public: struct SignalHook { inline SignalHook() : obj(0), midx(-1) { } - QString owner, service, path, signature; + QString service, path, signature; QObject* obj; int midx; QList<int> params; @@ -155,7 +155,13 @@ public: typedef QMultiHash<QString, SignalHook> SignalHookHash; typedef QHash<QString, QDBusMetaObject* > MetaObjectHash; typedef QHash<QByteArray, int> MatchRefCountHash; - typedef QHash<QString, int> WatchedServicesHash; + + struct WatchedServiceData { + WatchedServiceData() : refcount(0) {} + QString owner; + int refcount; + }; + typedef QHash<QString, WatchedServiceData> WatchedServicesHash; public: // public methods are entry points from other objects @@ -177,7 +183,7 @@ public: QDBusPendingCallPrivate *sendWithReplyAsync(const QDBusMessage &message, int timeout = -1); int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver, const char *returnMethod, const char *errorMethod, int timeout = -1); - bool connectSignal(const QString &service, const QString &owner, const QString &path, const QString& interface, + bool connectSignal(const QString &service, const QString &path, const QString& interface, const QString &name, const QStringList &argumentMatch, const QString &signature, QObject *receiver, const char *slot); void connectSignal(const QString &key, const SignalHook &hook); @@ -186,10 +192,10 @@ public: const QString &name, const QStringList &argumentMatch, const QString &signature, QObject *receiver, const char *slot); void registerObject(const ObjectTreeNode *node); - void connectRelay(const QString &service, const QString ¤tOwner, + void connectRelay(const QString &service, const QString &path, const QString &interface, QDBusAbstractInterface *receiver, const char *signal); - void disconnectRelay(const QString &service, const QString ¤tOwner, + void disconnectRelay(const QString &service, const QString &path, const QString &interface, QDBusAbstractInterface *receiver, const char *signal); @@ -223,6 +229,8 @@ private: bool isServiceRegisteredByThread(const QString &serviceName) const; + QString getNameOwnerNoCache(const QString &service); + protected: void customEvent(QEvent *e); void timerEvent(QTimerEvent *e); @@ -271,7 +279,7 @@ public: QDBusError lastError; QStringList serviceNames; - WatchedServicesHash watchedServiceNames; + WatchedServicesHash watchedServices; SignalHookHash signalHooks; MatchRefCountHash matchRefCounts; ObjectTreeNode rootNode; @@ -284,7 +292,7 @@ public: // static methods static int findSlot(QObject *obj, const QByteArray &normalizedName, QList<int>& params); static bool prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key, - const QString &service, const QString &owner, + const QString &service, const QString &path, const QString &interface, const QString &name, const QStringList &argMatch, QObject *receiver, const char *signal, int minMIdx, diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 40febc4..ea02005 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -390,7 +390,7 @@ static void qDBusNewConnection(DBusServer *server, DBusConnection *connection, v } // extern "C" -static QByteArray buildMatchRule(const QString &service, const QString & /*owner*/, +static QByteArray buildMatchRule(const QString &service, const QString &objectPath, const QString &interface, const QString &member, const QStringList &argMatch, const QString & /*signature*/) { @@ -523,7 +523,7 @@ qDBusSignalFilter(DBusConnection *connection, DBusMessage *message, void *data) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(message); - qDBusDebug() << QThread::currentThread() << "got message:" << amsg; + qDBusDebug() << d << "got message:" << amsg; return d->handleMessage(amsg) ? DBUS_HANDLER_RESULT_HANDLED : @@ -913,7 +913,7 @@ void QDBusConnectionPrivate::deliverCall(QObject *object, int /*flags*/, const Q if (msg.isReplyRequired() && !msg.isDelayedReply()) { if (!fail) { // normal reply - qDBusDebug() << QThread::currentThread() << "Automatically sending reply:" << outputArgs; + qDBusDebug() << this << "Automatically sending reply:" << outputArgs; send(msg.createReply(outputArgs)); } else { // generate internal error @@ -947,7 +947,6 @@ QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *p) QDBusMetaTypeId::init(); rootNode.flags = 0; - watchedServiceNames[QLatin1String(DBUS_SERVICE_DBUS)] = 1; } QDBusConnectionPrivate::~QDBusConnectionPrivate() @@ -1179,11 +1178,15 @@ void QDBusConnectionPrivate::_q_serviceOwnerChanged(const QString &name, { Q_UNUSED(oldOwner); QDBusWriteLocker locker(UpdateSignalHookOwnerAction, this); - QMutableHashIterator<QString, SignalHook> it(signalHooks); - it.toFront(); - while (it.hasNext()) - if (it.next().value().service == name) - it.value().owner = newOwner; + WatchedServicesHash::Iterator it = watchedServices.find(name); + if (it == watchedServices.end()) + return; + if (oldOwner != it->owner) + qWarning("QDBusConnection: name '%s' had owner '%s' but we thought it was '%s'", + qPrintable(name), qPrintable(oldOwner), qPrintable(it->owner)); + + qDBusDebug() << this << "Updating name" << name << "from" << oldOwner << "to" << newOwner; + it->owner = newOwner; } int QDBusConnectionPrivate::findSlot(QObject* obj, const QByteArray &normalizedName, @@ -1201,7 +1204,7 @@ int QDBusConnectionPrivate::findSlot(QObject* obj, const QByteArray &normalizedN } bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key, - const QString &service, const QString &owner, + const QString &service, const QString &path, const QString &interface, const QString &name, const QStringList &argMatch, QObject *receiver, const char *signal, int minMIdx, @@ -1220,7 +1223,6 @@ bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hoo } hook.service = service; - hook.owner = owner; // we don't care if the service has an owner yet hook.path = path; hook.obj = receiver; hook.argumentMatch = argMatch; @@ -1245,7 +1247,7 @@ bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hoo hook.signature += QLatin1String( QDBusMetaType::typeToSignature( hook.params.at(i) ) ); } - hook.matchRule = buildMatchRule(service, owner, path, interface, mname, argMatch, hook.signature); + hook.matchRule = buildMatchRule(service, path, interface, mname, argMatch, hook.signature); return true; // connect to this signal } @@ -1488,8 +1490,14 @@ void QDBusConnectionPrivate::handleSignal(const QString &key, const QDBusMessage //qDBusDebug() << signalHooks.keys(); for ( ; it != end && it.key() == key; ++it) { const SignalHook &hook = it.value(); - if (!hook.owner.isNull() && hook.owner != msg.service()) - continue; + if (!hook.service.isEmpty()) { + const QString owner = + shouldWatchService(hook.service) ? + watchedServices.value(hook.service).owner : + hook.service; + if (owner != msg.service()) + continue; + } if (!hook.path.isEmpty() && hook.path != msg.path()) continue; if (!hook.signature.isEmpty() && hook.signature != msg.signature()) @@ -1652,15 +1660,18 @@ void QDBusConnectionPrivate::setConnection(DBusConnection *dbc, const QDBusError } QString busService = QLatin1String(DBUS_SERVICE_DBUS); - connectSignal(busService, QString(), QString(), QString(), QLatin1String("NameAcquired"), QStringList(), QString(), + WatchedServicesHash::mapped_type &bus = watchedServices[busService]; + bus.refcount = 1; + bus.owner = getNameOwnerNoCache(busService); + connectSignal(busService, QString(), QString(), QLatin1String("NameAcquired"), QStringList(), QString(), this, SLOT(registerService(QString))); - connectSignal(busService, QString(), QString(), QString(), QLatin1String("NameLost"), QStringList(), QString(), + connectSignal(busService, QString(), QString(), QLatin1String("NameLost"), QStringList(), QString(), this, SLOT(unregisterService(QString))); q_dbus_connection_add_filter(connection, qDBusSignalFilter, this, 0); - //qDebug("base service: %s", service); + qDBusDebug() << this << ": connected successfully"; // schedule a dispatch: QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection); @@ -1695,7 +1706,7 @@ void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call) msg = QDBusMessagePrivate::fromDBusMessage(reply); q_dbus_message_unref(reply); } - qDBusDebug() << QThread::currentThread() << "got message reply (async):" << msg; + qDBusDebug() << connection << "got message reply (async):" << msg; // Check if the reply has the expected signature call->checkReceivedSignature(); @@ -1763,7 +1774,7 @@ int QDBusConnectionPrivate::send(const QDBusMessage& message) q_dbus_message_set_no_reply(msg, true); // the reply would not be delivered to anything - qDBusDebug() << QThread::currentThread() << "sending message (no reply):" << message; + qDBusDebug() << this << "sending message (no reply):" << message; checkThread(); bool isOk = q_dbus_connection_send(connection, msg, 0); int serial = 0; @@ -1795,7 +1806,7 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message, return QDBusMessage::createError(err); } - qDBusDebug() << QThread::currentThread() << "sending message (blocking):" << message; + qDBusDebug() << this << "sending message (blocking):" << message; QDBusErrorInternal error; DBusMessage *reply = q_dbus_connection_send_with_reply_and_block(connection, msg, timeout, error); @@ -1808,7 +1819,7 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message, QDBusMessage amsg = QDBusMessagePrivate::fromDBusMessage(reply); q_dbus_message_unref(reply); - qDBusDebug() << QThread::currentThread() << "got message reply (blocking):" << amsg; + qDBusDebug() << this << "got message reply (blocking):" << amsg; return amsg; } else { // use the event loop @@ -1835,7 +1846,7 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message, QDBusMessage QDBusConnectionPrivate::sendWithReplyLocal(const QDBusMessage &message) { - qDBusDebug() << QThread::currentThread() << "sending message via local-loop:" << message; + qDBusDebug() << this << "sending message via local-loop:" << message; QDBusMessage localCallMsg = QDBusMessagePrivate::makeLocal(*this, message); bool handled = handleMessage(localCallMsg); @@ -1862,7 +1873,7 @@ QDBusMessage QDBusConnectionPrivate::sendWithReplyLocal(const QDBusMessage &mess } // there is a reply - qDBusDebug() << QThread::currentThread() << "got message via local-loop:" << localReplyMsg; + qDBusDebug() << this << "got message via local-loop:" << localReplyMsg; return localReplyMsg; } @@ -1896,7 +1907,7 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM return pcall; } - qDBusDebug() << QThread::currentThread() << "sending message (async):" << message; + qDBusDebug() << this << "sending message (async):" << message; DBusPendingCall *pending = 0; QDBusDispatchLocker locker(SendWithReplyAsyncAction, this); @@ -1968,7 +1979,7 @@ int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObj return 1; } -bool QDBusConnectionPrivate::connectSignal(const QString &service, const QString &owner, +bool QDBusConnectionPrivate::connectSignal(const QString &service, const QString &path, const QString &interface, const QString &name, const QStringList &argumentMatch, const QString &signature, QObject *receiver, const char *slot) @@ -1981,7 +1992,7 @@ bool QDBusConnectionPrivate::connectSignal(const QString &service, const QString name2.detach(); hook.signature = signature; - if (!prepareHook(hook, key, service, owner, path, interface, name, argumentMatch, receiver, slot, 0, false)) + if (!prepareHook(hook, key, service, path, interface, name, argumentMatch, receiver, slot, 0, false)) return false; // don't connect // avoid duplicating: @@ -1990,7 +2001,6 @@ bool QDBusConnectionPrivate::connectSignal(const QString &service, const QString for ( ; it != end && it.key() == key; ++it) { const QDBusConnectionPrivate::SignalHook &entry = it.value(); if (entry.service == hook.service && - entry.owner == hook.owner && entry.path == hook.path && entry.signature == hook.signature && entry.obj == hook.obj && @@ -2035,16 +2045,19 @@ void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook // Successfully connected the signal // Do we need to watch for this name? if (shouldWatchService(hook.service)) { - WatchedServicesHash::Iterator it = watchedServiceNames.find(hook.service); - if (it != watchedServiceNames.end()) { + WatchedServicesHash::mapped_type &data = watchedServices[hook.service]; + if (data.refcount) { // already watching - ++it.value(); + ++data.refcount; } else { // we need to watch for this service changing QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS); - connectSignal(dbusServerService, dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS), + connectSignal(dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS), QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(), this, SLOT(_q_serviceOwnerChanged(QString,QString,QString))); + data.owner = getNameOwnerNoCache(hook.service); + qDBusDebug() << this << "Watching service" << hook.service << "for owner changes (current owner:" + << data.owner << ")"; } } } @@ -2064,7 +2077,7 @@ bool QDBusConnectionPrivate::disconnectSignal(const QString &service, name2.detach(); hook.signature = signature; - if (!prepareHook(hook, key, service, QString(), path, interface, name, argumentMatch, receiver, slot, 0, false)) + if (!prepareHook(hook, key, service, path, interface, name, argumentMatch, receiver, slot, 0, false)) return false; // don't disconnect // avoid duplicating: @@ -2073,7 +2086,6 @@ bool QDBusConnectionPrivate::disconnectSignal(const QString &service, for ( ; it != end && it.key() == key; ++it) { const QDBusConnectionPrivate::SignalHook &entry = it.value(); if (entry.service == hook.service && - //entry.owner == hook.owner && entry.path == hook.path && entry.signature == hook.signature && entry.obj == hook.obj && @@ -2093,16 +2105,16 @@ QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it) { const SignalHook &hook = it.value(); - WatchedServicesHash::Iterator sit = watchedServiceNames.find(hook.service); - if (sit != watchedServiceNames.end()) { - if (sit.value() == 1) { - watchedServiceNames.erase(sit); + WatchedServicesHash::Iterator sit = watchedServices.find(hook.service); + if (sit != watchedServices.end()) { + if (sit.value().refcount == 1) { + watchedServices.erase(sit); QString dbusServerService = QLatin1String(DBUS_SERVICE_DBUS); disconnectSignal(dbusServerService, QString(), QLatin1String(DBUS_INTERFACE_DBUS), QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(), this, SLOT(_q_serviceOwnerChanged(QString,QString,QString))); } else { - --sit.value(); + --sit.value().refcount; } } @@ -2154,7 +2166,7 @@ void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node) } } -void QDBusConnectionPrivate::connectRelay(const QString &service, const QString &owner, +void QDBusConnectionPrivate::connectRelay(const QString &service, const QString &path, const QString &interface, QDBusAbstractInterface *receiver, const char *signal) @@ -2164,7 +2176,7 @@ void QDBusConnectionPrivate::connectRelay(const QString &service, const QString SignalHook hook; QString key; - if (!prepareHook(hook, key, service, owner, path, interface, QString(), QStringList(), receiver, signal, + if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, signal, QDBusAbstractInterface::staticMetaObject.methodCount(), true)) return; // don't connect @@ -2175,7 +2187,6 @@ void QDBusConnectionPrivate::connectRelay(const QString &service, const QString for ( ; it != end && it.key() == key; ++it) { const SignalHook &entry = it.value(); if (entry.service == hook.service && - entry.owner == hook.owner && entry.path == hook.path && entry.signature == hook.signature && entry.obj == hook.obj && @@ -2186,7 +2197,7 @@ void QDBusConnectionPrivate::connectRelay(const QString &service, const QString connectSignal(key, hook); } -void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QString &owner, +void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QString &path, const QString &interface, QDBusAbstractInterface *receiver, const char *signal) @@ -2196,7 +2207,7 @@ void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QStri SignalHook hook; QString key; - if (!prepareHook(hook, key, service, owner, path, interface, QString(), QStringList(), receiver, signal, + if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, signal, QDBusAbstractInterface::staticMetaObject.methodCount(), true)) return; // don't connect @@ -2207,7 +2218,6 @@ void QDBusConnectionPrivate::disconnectRelay(const QString &service, const QStri for ( ; it != end && it.key() == key; ++it) { const SignalHook &entry = it.value(); if (entry.service == hook.service && - entry.owner == hook.owner && entry.path == hook.path && entry.signature == hook.signature && entry.obj == hook.obj && @@ -2225,9 +2235,23 @@ QString QDBusConnectionPrivate::getNameOwner(const QString& serviceName) { if (QDBusUtil::isValidUniqueConnectionName(serviceName)) return serviceName; - if (!connection || !QDBusUtil::isValidBusName(serviceName)) + if (!connection) return QString(); + { + // acquire a read lock for the cache + QReadLocker locker(&lock); + WatchedServicesHash::ConstIterator it = watchedServices.constFind(serviceName); + if (it != watchedServices.constEnd()) + return it->owner; + } + + // not cached + return getNameOwnerNoCache(serviceName); +} + +QString QDBusConnectionPrivate::getNameOwnerNoCache(const QString &serviceName) +{ QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String(DBUS_SERVICE_DBUS), QLatin1String(DBUS_PATH_DBUS), QLatin1String(DBUS_INTERFACE_DBUS), QLatin1String("GetNameOwner")); diff --git a/src/dbus/qdbusmarshaller.cpp b/src/dbus/qdbusmarshaller.cpp index d732ad0..28cec7d 100644 --- a/src/dbus/qdbusmarshaller.cpp +++ b/src/dbus/qdbusmarshaller.cpp @@ -387,7 +387,6 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg) switch (*signature) { #ifdef __OPTIMIZE__ case DBUS_TYPE_BYTE: - case DBUS_TYPE_BOOLEAN: case DBUS_TYPE_INT16: case DBUS_TYPE_UINT16: case DBUS_TYPE_INT32: @@ -397,6 +396,9 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg) case DBUS_TYPE_DOUBLE: qIterAppend(&iterator, ba, *signature, arg.constData()); return true; + case DBUS_TYPE_BOOLEAN: + append( arg.toBool() ); + return true; #else case DBUS_TYPE_BYTE: append( qvariant_cast<uchar>(arg) ); diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp index ef50b04..9c768ed 100644 --- a/src/dbus/qdbuspendingcall.cpp +++ b/src/dbus/qdbuspendingcall.cpp @@ -310,7 +310,7 @@ QDBusPendingCall &QDBusPendingCall::operator=(const QDBusPendingCall &other) bool QDBusPendingCall::isFinished() const { - return d && (d->replyMessage.type() != QDBusMessage::InvalidMessage); + return !d || (d->replyMessage.type() != QDBusMessage::InvalidMessage); } void QDBusPendingCall::waitForFinished() diff --git a/src/dbus/qdbuspendingreply.h b/src/dbus/qdbuspendingreply.h index b7f54e4..4f90c98 100644 --- a/src/dbus/qdbuspendingreply.h +++ b/src/dbus/qdbuspendingreply.h @@ -188,6 +188,7 @@ public: private: inline void calculateMetaTypes() { + if (!d) return; int typeIds[Count > 0 ? Count : 1]; // use at least one since zero-sized arrays aren't valid ForEach::fillMetaTypes(typeIds); setMetaTypes(Count, typeIds); diff --git a/src/gui/dialogs/qcolordialog_mac.mm b/src/gui/dialogs/qcolordialog_mac.mm index 53d2e1e..a350be1 100644 --- a/src/gui/dialogs/qcolordialog_mac.mm +++ b/src/gui/dialogs/qcolordialog_mac.mm @@ -79,6 +79,7 @@ QT_USE_NAMESPACE BOOL mHackedPanel; NSInteger mResultCode; BOOL mDialogIsExecuting; + BOOL mResultSet; } - (id)initWithColorPanel:(NSColorPanel *)panel stolenContentView:(NSView *)stolenContentView @@ -116,6 +117,7 @@ QT_USE_NAMESPACE mHackedPanel = (okButton != 0); mResultCode = NSCancelButton; mDialogIsExecuting = false; + mResultSet = false; if (mHackedPanel) { [self relayout]; @@ -159,11 +161,13 @@ QT_USE_NAMESPACE - (BOOL)windowShouldClose:(id)window { Q_UNUSED(window); - if (mHackedPanel) { - [self onCancelClicked]; - } else { + if (!mHackedPanel) [self updateQtColor]; + if (mDialogIsExecuting) { [self finishOffWithCode:NSCancelButton]; + } else { + mResultSet = true; + mPriv->colorDialog()->reject(); } return true; } @@ -240,11 +244,12 @@ QT_USE_NAMESPACE - (void)onCancelClicked { - Q_ASSERT(mHackedPanel); - [[mStolenContentView window] close]; - delete mQtColor; - mQtColor = new QColor(); - [self finishOffWithCode:NSCancelButton]; + if (mHackedPanel) { + [[mStolenContentView window] close]; + delete mQtColor; + mQtColor = new QColor(); + [self finishOffWithCode:NSCancelButton]; + } } - (void)updateQtColor @@ -306,10 +311,16 @@ QT_USE_NAMESPACE } else { // Since we are not in a modal event loop, we can safely close // down QColorDialog - if (mResultCode == NSCancelButton) - mPriv->colorDialog()->reject(); - else - mPriv->colorDialog()->accept(); + // Calling accept() or reject() can in turn call closeCocoaColorPanel. + // This check will prevent any such recursion. + if (!mResultSet) { + mResultSet = true; + if (mResultCode == NSCancelButton) { + mPriv->colorDialog()->reject(); + } else { + mPriv->colorDialog()->accept(); + } + } } } @@ -336,6 +347,7 @@ QT_USE_NAMESPACE } } + QAbstractEventDispatcher::instance()->interrupt(); if (mResultCode == NSCancelButton) mPriv->colorDialog()->reject(); else diff --git a/src/gui/dialogs/qfiledialog.cpp b/src/gui/dialogs/qfiledialog.cpp index 45a410f..3c388de 100644 --- a/src/gui/dialogs/qfiledialog.cpp +++ b/src/gui/dialogs/qfiledialog.cpp @@ -669,6 +669,9 @@ void QFileDialog::setOptions(Options options) } if (changed & HideNameFilterDetails) setNameFilters(d->nameFilters); + + if (changed & ShowDirsOnly) + setFilter((options & ShowDirsOnly) ? filter() & ~QDir::Files : filter() | QDir::Files); } QFileDialog::Options QFileDialog::options() const @@ -995,6 +998,24 @@ bool QFileDialog::isNameFilterDetailsVisible() const } +/* + Strip the filters by removing the details, e.g. (*.*). +*/ +QStringList qt_strip_filters(const QStringList &filters) +{ + QStringList strippedFilters; + QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp)); + for (int i = 0; i < filters.count(); ++i) { + QString filterName; + int index = r.indexIn(filters[i]); + if (index >= 0) + filterName = r.cap(1); + strippedFilters.append(filterName.simplified()); + } + return strippedFilters; +} + + /*! \since 4.4 @@ -1021,20 +1042,11 @@ void QFileDialog::setNameFilters(const QStringList &filters) if (cleanedFilters.isEmpty()) return; - if (testOption(HideNameFilterDetails)) { - QStringList strippedFilters; - QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp)); - for (int i = 0; i < cleanedFilters.count(); ++i) { - QString filterName; - int index = r.indexIn(cleanedFilters[i]); - if (index >= 0) - filterName = r.cap(1); - strippedFilters.append(filterName.simplified()); - } - d->qFileDialogUi->fileTypeCombo->addItems(strippedFilters); - } else { + if (testOption(HideNameFilterDetails)) + d->qFileDialogUi->fileTypeCombo->addItems(qt_strip_filters(cleanedFilters)); + else d->qFileDialogUi->fileTypeCombo->addItems(cleanedFilters); - } + d->_q_useNameFilter(0); } @@ -1085,8 +1097,12 @@ void QFileDialog::selectNameFilter(const QString &filter) d->selectNameFilter_sys(filter); return; } - - int i = d->qFileDialogUi->fileTypeCombo->findText(filter); + int i; + if (testOption(HideNameFilterDetails)) { + i = d->qFileDialogUi->fileTypeCombo->findText(qt_strip_filters(qt_make_filter_list(filter)).first()); + } else { + i = d->qFileDialogUi->fileTypeCombo->findText(filter); + } if (i >= 0) { d->qFileDialogUi->fileTypeCombo->setCurrentIndex(i); d->_q_useNameFilter(d->qFileDialogUi->fileTypeCombo->currentIndex()); diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp index 8e78503..6ec80a9 100644 --- a/src/gui/dialogs/qfilesystemmodel.cpp +++ b/src/gui/dialogs/qfilesystemmodel.cpp @@ -1223,8 +1223,7 @@ bool QFileSystemModel::dropMimeData(const QMimeData *data, Qt::DropAction action case Qt::MoveAction: for (; it != urls.constEnd(); ++it) { QString path = (*it).toLocalFile(); - success = QFile::copy(path, to + QFileInfo(path).fileName()) - && QFile::remove(path) && success; + success = QFile::rename(path, to + QFileInfo(path).fileName()) && success; } break; default: @@ -1779,7 +1778,7 @@ void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, const QL node->fileName = fileName; } - if (info.size() == -1) { + if (info.size() == -1 && !info.isSymLink()) { removeNode(parentNode, fileName); continue; } diff --git a/src/gui/dialogs/qfilesystemmodel_p.h b/src/gui/dialogs/qfilesystemmodel_p.h index 175159f..68e19dc 100644 --- a/src/gui/dialogs/qfilesystemmodel_p.h +++ b/src/gui/dialogs/qfilesystemmodel_p.h @@ -238,15 +238,15 @@ public: void sortChildren(int column, const QModelIndex &parent); inline int translateVisibleLocation(QFileSystemNode *parent, int row) const { - if (sortOrder == Qt::AscendingOrder) - return row; - if (parent->dirtyChildrenIndex == -1 || row < parent->dirtyChildrenIndex) - if (parent->dirtyChildrenIndex != -1) - return parent->dirtyChildrenIndex - row - 1; - else + if (sortOrder != Qt::AscendingOrder) { + if (parent->dirtyChildrenIndex == -1) return parent->visibleChildren.count() - row - 1; - else - return row; + + if (row < parent->dirtyChildrenIndex) + return parent->dirtyChildrenIndex - row - 1; + } + + return row; } inline static QString myComputer() { diff --git a/src/gui/dialogs/qfontdialog_mac.mm b/src/gui/dialogs/qfontdialog_mac.mm index 0c467cd..31bab2b 100644 --- a/src/gui/dialogs/qfontdialog_mac.mm +++ b/src/gui/dialogs/qfontdialog_mac.mm @@ -394,7 +394,9 @@ static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont) } [mFontPanel setDelegate:nil]; [[NSFontManager sharedFontManager] setDelegate:nil]; +#ifdef QT_MAC_USE_COCOA [[NSFontManager sharedFontManager] setTarget:nil]; +#endif } @end @@ -518,7 +520,9 @@ void *QFontDialogPrivate::openCocoaFontPanel(const QFont &initial, extraHeight:dialogExtraHeight]; [ourPanel setDelegate:delegate]; [[NSFontManager sharedFontManager] setDelegate:delegate]; +#ifdef QT_MAC_USE_COCOA [[NSFontManager sharedFontManager] setTarget:delegate]; +#endif setFont(delegate, initial); // hack to get correct initial layout diff --git a/src/gui/dialogs/qmessagebox.cpp b/src/gui/dialogs/qmessagebox.cpp index a318c43..8ec8d1c 100644 --- a/src/gui/dialogs/qmessagebox.cpp +++ b/src/gui/dialogs/qmessagebox.cpp @@ -188,6 +188,9 @@ public: bool autoAddOkButton; QAbstractButton *detectedEscapeButton; QLabel *informativeLabel; +#ifdef Q_OS_SYMBIAN + QTextEdit *textEdit; +#endif QPointer<QObject> receiverToDisconnectOnClose; QByteArray memberToDisconnectOnClose; QByteArray signalToDisconnectOnClose; @@ -2459,10 +2462,24 @@ void QMessageBox::setInformativeText(const QString &text) #endif label->setWordWrap(true); QGridLayout *grid = static_cast<QGridLayout *>(layout()); +#ifdef Q_OS_SYMBIAN + label->hide(); + QTextEdit *textEdit = new QTextEdit(this); + textEdit->setReadOnly(true); + grid->addWidget(textEdit, 1, 1, 1, 1); + d->textEdit = textEdit; +#else grid->addWidget(label, 1, 1, 1, 1); +#endif d->informativeLabel = label; } d->informativeLabel->setText(text); + +#ifdef Q_OS_SYMBIAN + //We need to put the informative label inside textEdit to enable scrolling of long texts. + d->textEdit->setText(d->informativeLabel->text()); +#endif + d->updateSize(); } diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index 239e29c..a523bab 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -160,6 +160,10 @@ QRectF QGraphicsEffectSource::boundingRect(Qt::CoordinateSystem system) const /*! Returns the bounding rectangle of the source mapped to the given \a system. + Calling this function with Qt::DeviceCoordinates outside of + QGraphicsEffect::draw() will give undefined results, as there is no device + context available. + \sa draw() */ QRectF QGraphicsEffect::sourceBoundingRect(Qt::CoordinateSystem system) const @@ -309,7 +313,10 @@ QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offse // Shortcut, no cache for childless pixmap items... const QGraphicsItem *item = graphicsItem(); if (system == Qt::LogicalCoordinates && mode == QGraphicsEffect::NoPad && item && isPixmap()) { - return ((QGraphicsPixmapItem *) item)->pixmap(); + const QGraphicsPixmapItem *pixmapItem = static_cast<const QGraphicsPixmapItem *>(item); + if (offset) + *offset = pixmapItem->offset().toPoint(); + return pixmapItem->pixmap(); } if (system == Qt::DeviceCoordinates && item @@ -348,6 +355,10 @@ QPixmap QGraphicsEffectSource::pixmap(Qt::CoordinateSystem system, QPoint *offse The returned pixmap is clipped to the current painter's device rectangle when \a system is Qt::DeviceCoordinates. + Calling this function with Qt::DeviceCoordinates outside of + QGraphicsEffect::draw() will give undefined results, as there is no device + context available. + \sa draw(), boundingRect() */ QPixmap QGraphicsEffect::sourcePixmap(Qt::CoordinateSystem system, QPoint *offset, QGraphicsEffect::PixmapPadMode mode) const @@ -363,10 +374,14 @@ QGraphicsEffectSourcePrivate::~QGraphicsEffectSourcePrivate() invalidateCache(); } -void QGraphicsEffectSourcePrivate::invalidateCache(bool effectRectChanged) const +void QGraphicsEffectSourcePrivate::invalidateCache(InvalidateReason reason) const { - if (effectRectChanged && m_cachedMode != QGraphicsEffect::PadToEffectiveBoundingRect) + if (m_cachedMode != QGraphicsEffect::PadToEffectiveBoundingRect + && (reason == EffectRectChanged + || reason == TransformChanged + && m_cachedSystem == Qt::LogicalCoordinates)) return; + QPixmapCache::remove(m_cacheKey); } @@ -398,8 +413,8 @@ QGraphicsEffect::~QGraphicsEffect() /*! Returns the effective bounding rectangle for this effect, i.e., the - bounding rectangle of the source, adjusted by any margins applied by - the effect itself. + bounding rectangle of the source in device coordinates, adjusted by + any margins applied by the effect itself. \sa boundingRectFor(), updateBoundingRect() */ @@ -413,7 +428,7 @@ QRectF QGraphicsEffect::boundingRect() const /*! Returns the effective bounding rectangle for this effect, given the - provided \a rect in the source's coordinate space. When writing + provided \a rect in the device coordinates. When writing you own custom effect, you must call updateBoundingRect() whenever any parameters are changed that may cause this this function to return a different value. @@ -512,7 +527,7 @@ void QGraphicsEffect::updateBoundingRect() Q_D(QGraphicsEffect); if (d->source) { d->source->d_func()->effectBoundingRectChanged(); - d->source->d_func()->invalidateCache(true); + d->source->d_func()->invalidateCache(QGraphicsEffectSourcePrivate::EffectRectChanged); } } @@ -829,22 +844,19 @@ QRectF QGraphicsBlurEffect::boundingRectFor(const QRectF &rect) const void QGraphicsBlurEffect::draw(QPainter *painter) { Q_D(QGraphicsBlurEffect); - if (d->filter->radius() <= 0) { + if (d->filter->radius() < 1) { drawSource(painter); return; } PixmapPadMode mode = PadToEffectiveBoundingRect; if (painter->paintEngine()->type() == QPaintEngine::OpenGL2) - mode = PadToTransparentBorder; + mode = NoPad; // Draw pixmap in device coordinates to avoid pixmap scaling. QPoint offset; - const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset, mode); - QTransform restoreTransform = painter->worldTransform(); - painter->setWorldTransform(QTransform()); + QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, mode); d->filter->draw(painter, offset, pixmap); - painter->setWorldTransform(restoreTransform); } /*! @@ -1025,7 +1037,7 @@ void QGraphicsDropShadowEffect::draw(QPainter *painter) PixmapPadMode mode = PadToEffectiveBoundingRect; if (painter->paintEngine()->type() == QPaintEngine::OpenGL2) - mode = PadToTransparentBorder; + mode = NoPad; // Draw pixmap in device coordinates to avoid pixmap scaling. QPoint offset; diff --git a/src/gui/effects/qgraphicseffect_p.h b/src/gui/effects/qgraphicseffect_p.h index 0011eef..cab7a48 100644 --- a/src/gui/effects/qgraphicseffect_p.h +++ b/src/gui/effects/qgraphicseffect_p.h @@ -108,6 +108,13 @@ public: , m_cachedMode(QGraphicsEffect::PadToTransparentBorder) {} + enum InvalidateReason + { + TransformChanged, + EffectRectChanged, + SourceChanged + }; + virtual ~QGraphicsEffectSourcePrivate(); virtual void detach() = 0; virtual QRectF boundingRect(Qt::CoordinateSystem system) const = 0; @@ -121,7 +128,9 @@ public: virtual QPixmap pixmap(Qt::CoordinateSystem system, QPoint *offset = 0, QGraphicsEffect::PixmapPadMode mode = QGraphicsEffect::PadToTransparentBorder) const = 0; virtual void effectBoundingRectChanged() = 0; - void invalidateCache(bool effectRectChanged = false) const; + + void invalidateCache(InvalidateReason reason = SourceChanged) const; + Qt::CoordinateSystem currentCachedSystem() const { return m_cachedSystem; } friend class QGraphicsScenePrivate; friend class QGraphicsItem; diff --git a/src/gui/embedded/directfb.pri b/src/gui/embedded/directfb.pri index 84253b5..bd1d947 100644 --- a/src/gui/embedded/directfb.pri +++ b/src/gui/embedded/directfb.pri @@ -14,6 +14,7 @@ #DEFINES += QT_NO_DIRECTFB_KEYBOARD #DEFINES += QT_DIRECTFB_TIMING #DEFINES += QT_NO_DIRECTFB_OPAQUE_DETECTION +#DEFINES += QT_NO_DIRECTFB_STRETCHBLIT #DIRECTFB_DRAWINGOPERATIONS=DRAW_RECTS|DRAW_LINES|DRAW_IMAGE|DRAW_PIXMAP|DRAW_TILED_PIXMAP|STROKE_PATH|DRAW_PATH|DRAW_POINTS|DRAW_ELLIPSE|DRAW_POLYGON|DRAW_TEXT|FILL_PATH|FILL_RECT|DRAW_COLORSPANS|DRAW_ROUNDED_RECT #DEFINES += \"QT_DIRECTFB_WARN_ON_RASTERFALLBACKS=$$DIRECTFB_DRAWINGOPERATIONS\" #DEFINES += \"QT_DIRECTFB_DISABLE_RASTERFALLBACKS=$$DIRECTFB_DRAWINGOPERATIONS\" diff --git a/src/gui/embedded/qscreen_qws.cpp b/src/gui/embedded/qscreen_qws.cpp index ae5570f..07bb258 100644 --- a/src/gui/embedded/qscreen_qws.cpp +++ b/src/gui/embedded/qscreen_qws.cpp @@ -3150,6 +3150,7 @@ int QScreen::subScreenIndexAt(const QPoint &p) const #if 0 #ifdef QT_LOADABLE_MODULES +#include <dlfcn.h> // ### needs update after driver init changes diff --git a/src/gui/embedded/qscreen_qws.h b/src/gui/embedded/qscreen_qws.h index b3246f9..7ab49fb 100644 --- a/src/gui/embedded/qscreen_qws.h +++ b/src/gui/embedded/qscreen_qws.h @@ -243,7 +243,9 @@ public: int totalSize() const { return mapsize; } QRgb * clut() { return screenclut; } +#ifdef QT_DEPRECATED QT_DEPRECATED int numCols() { return screencols; } +#endif int colorCount() { return screencols; } virtual QSize mapToDevice(const QSize &) const; diff --git a/src/gui/graphicsview/qgraphicsanchorlayout.cpp b/src/gui/graphicsview/qgraphicsanchorlayout.cpp index 6718a28..f504c54 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout.cpp @@ -321,14 +321,14 @@ void QGraphicsAnchorLayout::addCornerAnchors(QGraphicsLayoutItem *firstItem, // Horizontal anchor Qt::AnchorPoint firstEdge = (firstCorner & 1 ? Qt::AnchorRight: Qt::AnchorLeft); Qt::AnchorPoint secondEdge = (secondCorner & 1 ? Qt::AnchorRight: Qt::AnchorLeft); - d->addAnchor(firstItem, firstEdge, secondItem, secondEdge); + if (d->addAnchor(firstItem, firstEdge, secondItem, secondEdge)) { + // Vertical anchor + firstEdge = (firstCorner & 2 ? Qt::AnchorBottom: Qt::AnchorTop); + secondEdge = (secondCorner & 2 ? Qt::AnchorBottom: Qt::AnchorTop); + d->addAnchor(firstItem, firstEdge, secondItem, secondEdge); - // Vertical anchor - firstEdge = (firstCorner & 2 ? Qt::AnchorBottom: Qt::AnchorTop); - secondEdge = (secondCorner & 2 ? Qt::AnchorBottom: Qt::AnchorTop); - d->addAnchor(firstItem, firstEdge, secondItem, secondEdge); - - invalidate(); + invalidate(); + } } /*! @@ -351,11 +351,14 @@ void QGraphicsAnchorLayout::addAnchors(QGraphicsLayoutItem *firstItem, QGraphicsLayoutItem *secondItem, Qt::Orientations orientations) { + bool ok = true; if (orientations & Qt::Horizontal) { - addAnchor(secondItem, Qt::AnchorLeft, firstItem, Qt::AnchorLeft); - addAnchor(firstItem, Qt::AnchorRight, secondItem, Qt::AnchorRight); + // Currently, if the first is ok, then the rest of the calls should be ok + ok = addAnchor(secondItem, Qt::AnchorLeft, firstItem, Qt::AnchorLeft) != 0; + if (ok) + addAnchor(firstItem, Qt::AnchorRight, secondItem, Qt::AnchorRight); } - if (orientations & Qt::Vertical) { + if (orientations & Qt::Vertical && ok) { addAnchor(secondItem, Qt::AnchorTop, firstItem, Qt::AnchorTop); addAnchor(firstItem, Qt::AnchorBottom, secondItem, Qt::AnchorBottom); } diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index 03ed63d..1dc6873 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -1666,6 +1666,13 @@ QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *fi return 0; } + const QGraphicsLayoutItem *parentWidget = q->parentLayoutItem(); + if (firstItem == parentWidget || secondItem == parentWidget) { + qWarning("QGraphicsAnchorLayout::addAnchor(): " + "You cannot add the parent of the layout to the layout."); + return 0; + } + // In QGraphicsAnchorLayout, items are represented in its internal // graph as four anchors that connect: // - Left -> HCenter diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 03e8b09..726d571 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2584,6 +2584,35 @@ void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect) /*! \internal \since 4.6 + Returns the effective bounding rect of the given item space rect. + If the item has no effect, the rect is returned unmodified. + If the item has an effect, the effective rect can be extend beyond the + item's bounding rect, depending on the effect. + + \sa boundingRect() +*/ +QRectF QGraphicsItemPrivate::effectiveBoundingRect(const QRectF &rect) const +{ +#ifndef QT_NO_GRAPHICSEFFECT + Q_Q(const QGraphicsItem); + QGraphicsEffect *effect = graphicsEffect; + if (scene && effect && effect->isEnabled()) { + QRectF sceneRect = q->mapRectToScene(rect); + QRectF sceneEffectRect; + foreach (QGraphicsView *view, scene->views()) { + QRectF deviceRect = view->d_func()->mapRectFromScene(sceneRect); + QRect deviceEffectRect = effect->boundingRectFor(deviceRect).toAlignedRect(); + sceneEffectRect |= view->d_func()->mapRectToScene(deviceEffectRect); + } + return q->mapRectFromScene(sceneEffectRect); + } +#endif //QT_NO_GRAPHICSEFFECT + return rect; +} + +/*! + \internal + \since 4.6 Returns the effective bounding rect of the item. If the item has no effect, this is the same as the item's bounding rect. If the item has an effect, the effective rect can be larger than the item's @@ -2594,16 +2623,19 @@ void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect) QRectF QGraphicsItemPrivate::effectiveBoundingRect() const { #ifndef QT_NO_GRAPHICSEFFECT - QGraphicsEffect *effect = graphicsEffect; - QRectF brect = effect && effect->isEnabled() ? effect->boundingRect() : q_ptr->boundingRect(); + Q_Q(const QGraphicsItem); + QRectF brect = effectiveBoundingRect(q_ptr->boundingRect()); if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) return brect; const QGraphicsItem *effectParent = parent; while (effectParent) { - effect = effectParent->d_ptr->graphicsEffect; - if (effect && effect->isEnabled()) - brect = effect->boundingRectFor(brect); + QGraphicsEffect *effect = effectParent->d_ptr->graphicsEffect; + if (scene && effect && effect->isEnabled()) { + const QRectF brectInParentSpace = q->mapRectToItem(effectParent, brect); + const QRectF effectRectInParentSpace = effectParent->d_ptr->effectiveBoundingRect(brectInParentSpace); + brect = effectParent->mapRectToItem(q, effectRectInParentSpace); + } if (effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) return brect; effectParent = effectParent->d_ptr->parent; @@ -7145,9 +7177,16 @@ void QGraphicsItem::prepareGeometryChange() QGraphicsItem *parent = this; while ((parent = parent->d_ptr->parent)) { - parent->d_ptr->dirtyChildrenBoundingRect = 1; + QGraphicsItemPrivate *parentp = parent->d_ptr.data(); + parentp->dirtyChildrenBoundingRect = 1; // ### Only do this if the parent's effect applies to the entire subtree. - parent->d_ptr->notifyBoundingRectChanged = 1; + parentp->notifyBoundingRectChanged = 1; +#ifndef QT_NO_GRAPHICSEFFECT + if (parentp->scene && parentp->graphicsEffect) { + parentp->notifyInvalidated = 1; + static_cast<QGraphicsItemEffectSourcePrivate *>(parentp->graphicsEffect->d_func()->source->d_func())->invalidateCache(); + } +#endif } } @@ -10505,6 +10544,20 @@ void QGraphicsItemGroup::addToGroup(QGraphicsItem *item) if (!item->pos().isNull()) newItemTransform *= QTransform::fromTranslate(-item->x(), -item->y()); + // removing additional transformations properties applied with itemTransform() + QPointF origin = item->transformOriginPoint(); + QMatrix4x4 m; + QList<QGraphicsTransform*> transformList = item->transformations(); + for (int i = 0; i < transformList.size(); ++i) + transformList.at(i)->applyTo(&m); + newItemTransform *= m.toTransform().inverted(); + newItemTransform.translate(origin.x(), origin.y()); + newItemTransform.rotate(-item->rotation()); + newItemTransform.scale(1/item->scale(), 1/item->scale()); + newItemTransform.translate(-origin.x(), -origin.y()); + + // ### Expensive, we could maybe use dirtySceneTransform bit for optimization + item->setTransform(newItemTransform); item->d_func()->setIsMemberOfGroup(true); prepareGeometryChange(); @@ -10529,11 +10582,39 @@ void QGraphicsItemGroup::removeFromGroup(QGraphicsItem *item) } QGraphicsItem *newParent = d_ptr->parent; + + // COMBINE + bool ok; + QTransform itemTransform; + if (newParent) + itemTransform = item->itemTransform(newParent, &ok); + else + itemTransform = item->sceneTransform(); + QPointF oldPos = item->mapToItem(newParent, 0, 0); item->setParentItem(newParent); - // ### This function should remap the item's matrix to keep the item's - // transformation unchanged relative to the scene. item->setPos(oldPos); + + // removing position from translation component of the new transform + if (!item->pos().isNull()) + itemTransform *= QTransform::fromTranslate(-item->x(), -item->y()); + + // removing additional transformations properties applied + // with itemTransform() or sceneTransform() + QPointF origin = item->transformOriginPoint(); + QMatrix4x4 m; + QList<QGraphicsTransform*> transformList = item->transformations(); + for (int i = 0; i < transformList.size(); ++i) + transformList.at(i)->applyTo(&m); + itemTransform *= m.toTransform().inverted(); + itemTransform.translate(origin.x(), origin.y()); + itemTransform.rotate(-item->rotation()); + itemTransform.scale(1 / item->scale(), 1 / item->scale()); + itemTransform.translate(-origin.x(), -origin.y()); + + // ### Expensive, we could maybe use dirtySceneTransform bit for optimization + + item->setTransform(itemTransform); item->d_func()->setIsMemberOfGroup(item->group() != 0); // ### Quite expensive. But removeFromGroup() isn't called very often. @@ -10643,26 +10724,45 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context"); return QPixmap(); } - if (!item->d_ptr->scene) return QPixmap(); QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func(); const QRectF sourceRect = boundingRect(system); - QRect effectRect; + QRectF effectRectF; + bool unpadded = false; if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) { - effectRect = item->graphicsEffect()->boundingRectFor(sourceRect).toAlignedRect(); + if (info) { + effectRectF = item->graphicsEffect()->boundingRectFor(boundingRect(Qt::DeviceCoordinates)); + unpadded = (effectRectF.size() == sourceRect.size()); + if (info && system == Qt::LogicalCoordinates) + effectRectF = info->painter->worldTransform().inverted().mapRect(effectRectF); + } else { + // no choice but to send a logical coordinate bounding rect to boundingRectFor + effectRectF = item->graphicsEffect()->boundingRectFor(sourceRect); + } } else if (mode == QGraphicsEffect::PadToTransparentBorder) { // adjust by 1.5 to account for cosmetic pens - effectRect = sourceRect.adjusted(-1.5, -1.5, 1.5, 1.5).toAlignedRect(); + effectRectF = sourceRect.adjusted(-1.5, -1.5, 1.5, 1.5); } else { - effectRect = sourceRect.toAlignedRect(); + effectRectF = sourceRect; + unpadded = true; } + QRect effectRect = effectRectF.toAlignedRect(); + if (offset) *offset = effectRect.topLeft(); + bool untransformed = !deviceCoordinates + || info->painter->worldTransform().type() <= QTransform::TxTranslate; + if (untransformed && unpadded && isPixmap()) { + if (offset) + *offset = boundingRect(system).topLeft().toPoint(); + return static_cast<QGraphicsPixmapItem *>(item)->pixmap(); + } + if (deviceCoordinates) { // Clip to viewport rect. int left, top, right, bottom; @@ -10690,12 +10790,6 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP if (effectRect.isEmpty()) return QPixmap(); - if (system == Qt::LogicalCoordinates - && effectRect.size() == sourceRect.size() - && isPixmap()) { - return static_cast<QGraphicsPixmapItem *>(item)->pixmap(); - } - QPixmap pixmap(effectRect.size()); pixmap.fill(Qt::transparent); QPainter pixmapPainter(&pixmap); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 8f9fe54..2d8de65 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -236,6 +236,8 @@ public: QRectF effectiveBoundingRect() const; QRectF sceneEffectiveBoundingRect() const; + QRectF effectiveBoundingRect(const QRectF &rect) const; + virtual void resolveFont(uint inheritedMask) { for (int i = 0; i < children.size(); ++i) diff --git a/src/gui/graphicsview/qgraphicslayout.cpp b/src/gui/graphicsview/qgraphicslayout.cpp index 2e9a30c..1e426c8 100644 --- a/src/gui/graphicsview/qgraphicslayout.cpp +++ b/src/gui/graphicsview/qgraphicslayout.cpp @@ -148,6 +148,10 @@ QT_BEGIN_NAMESPACE \a parent is passed to QGraphicsLayoutItem's constructor and the QGraphicsLayoutItem's isLayout argument is set to \e true. + + If \a parent is a QGraphicsWidget the layout will be installed + on that widget. (Note that installing a layout will delete the old one + installed.) */ QGraphicsLayout::QGraphicsLayout(QGraphicsLayoutItem *parent) : QGraphicsLayoutItem(*new QGraphicsLayoutPrivate) diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 2a53456..774a6d3 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -569,14 +569,10 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item) item->d_ptr->clearSubFocus(); - if (!item->d_ptr->inDestructor && item == tabFocusFirst) { - QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item); - widget->d_func()->fixFocusChainBeforeReparenting(0, 0); - } - if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges) unregisterScenePosItem(item); + QGraphicsScene *oldScene = item->d_func()->scene; item->d_func()->scene = 0; //We need to remove all children first because they might use their parent @@ -587,6 +583,11 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item) q->removeItem(item->d_ptr->children.at(i)); } + if (!item->d_ptr->inDestructor && item == tabFocusFirst) { + QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item); + widget->d_func()->fixFocusChainBeforeReparenting(0, oldScene, 0); + } + // Unregister focus proxy. item->d_ptr->resetFocusProxy(); @@ -1560,7 +1561,10 @@ QGraphicsScene::QGraphicsScene(qreal x, qreal y, qreal width, qreal height, QObj } /*! - Destroys the QGraphicsScene object. + Removes and deletes all items from the scene object + before destroying the scene object. The scene object + is removed from the application's global scene list, + and it is removed from all associated views. */ QGraphicsScene::~QGraphicsScene() { @@ -2442,23 +2446,26 @@ void QGraphicsScene::destroyItemGroup(QGraphicsItemGroup *group) } /*! - Adds or moves the item \a item and all its childen to the scene. + Adds or moves the \a item and all its childen to this scene. + This scene takes ownership of the \a item. If the item is visible (i.e., QGraphicsItem::isVisible() returns true), QGraphicsScene will emit changed() once control goes back to the event loop. - If the item is already in a different scene, it will first be removed from - its old scene, and then added to this scene as a top-level. + If the item is already in a different scene, it will first be + removed from its old scene, and then added to this scene as a + top-level. - QGraphicsScene will send ItemSceneChange notifications to \a item while - it is added to the scene. If item does not currently belong to a scene, only one - notification is sent. If it does belong to scene already (i.e., it is - moved to this scene), QGraphicsScene will send an addition notification as - the item is removed from its previous scene. + QGraphicsScene will send ItemSceneChange notifications to \a item + while it is added to the scene. If item does not currently belong + to a scene, only one notification is sent. If it does belong to + scene already (i.e., it is moved to this scene), QGraphicsScene + will send an addition notification as the item is removed from its + previous scene. - If the item is a panel, the scene is active, and there is no active panel - in the scene, then the item will be activated. + If the item is a panel, the scene is active, and there is no + active panel in the scene, then the item will be activated. \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(), addRect(), addText(), addWidget(), {QGraphicsItem#Sorting}{Sorting} @@ -4670,10 +4677,13 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * painter->setWorldTransform(*transformPtr); painter->setOpacity(opacity); - if (sourced->lastEffectTransform != painter->worldTransform()) { + if (sourced->currentCachedSystem() != Qt::LogicalCoordinates + && sourced->lastEffectTransform != painter->worldTransform()) + { sourced->lastEffectTransform = painter->worldTransform(); - sourced->invalidateCache(); + sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged); } + item->d_ptr->graphicsEffect->draw(painter); painter->setWorldTransform(restoreTransform); sourced->info = 0; @@ -5085,6 +5095,10 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0 + \obsolete Since Qt 4.6, this function is not called anymore unless + the QGraphicsView::IndirectPainting flag is given as an Optimization + flag. + \sa drawBackground(), drawForeground() */ void QGraphicsScene::drawItems(QPainter *painter, diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 3f9f443..c8f2c7c 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -217,7 +217,9 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < common side effect is that items that do draw with antialiasing can leave painting traces behind on the scene as they are moved. - \omitvalue IndirectPainting + \value IndirectPainting Since Qt 4.6, restore the old painting algorithm + that calls QGraphicsView::drawItems() and QGraphicsScene::drawItems(). + To be used only for compatibility with old code. */ /*! @@ -545,6 +547,32 @@ qint64 QGraphicsViewPrivate::verticalScroll() const /*! \internal + + Maps the given rectangle to the scene using QTransform::mapRect() +*/ +QRectF QGraphicsViewPrivate::mapRectToScene(const QRect &rect) const +{ + if (dirtyScroll) + const_cast<QGraphicsViewPrivate *>(this)->updateScroll(); + QRectF scrolled = QRectF(rect.translated(scrollX, scrollY)); + return identityMatrix ? scrolled : matrix.inverted().mapRect(scrolled); +} + + +/*! + \internal + + Maps the given rectangle from the scene using QTransform::mapRect() +*/ +QRectF QGraphicsViewPrivate::mapRectFromScene(const QRectF &rect) const +{ + if (dirtyScroll) + const_cast<QGraphicsViewPrivate *>(this)->updateScroll(); + return (identityMatrix ? rect : matrix.mapRect(rect)).translated(-scrollX, -scrollY); +} + +/*! + \internal */ void QGraphicsViewPrivate::updateScroll() { @@ -1182,6 +1210,11 @@ void QGraphicsView::setTransformationAnchor(ViewportAnchor anchor) { Q_D(QGraphicsView); d->transformationAnchor = anchor; + + // Ensure mouse tracking is enabled in the case we are using AnchorUnderMouse + // in order to have up-to-date information for centering the view. + if (d->transformationAnchor == AnchorUnderMouse) + d->viewport->setMouseTracking(true); } /*! @@ -1209,6 +1242,11 @@ void QGraphicsView::setResizeAnchor(ViewportAnchor anchor) { Q_D(QGraphicsView); d->resizeAnchor = anchor; + + // Ensure mouse tracking is enabled in the case we are using AnchorUnderMouse + // in order to have up-to-date information for centering the view. + if (d->resizeAnchor == AnchorUnderMouse) + d->viewport->setMouseTracking(true); } /*! @@ -2571,9 +2609,12 @@ void QGraphicsView::setupViewport(QWidget *widget) } // We are only interested in mouse tracking if items - // accept hover events or use non-default cursors. - if (d->scene && (!d->scene->d_func()->allItemsIgnoreHoverEvents - || !d->scene->d_func()->allItemsUseDefaultCursor)) { + // accept hover events or use non-default cursors or if + // AnchorUnderMouse is used as transformation or resize anchor. + if ((d->scene && (!d->scene->d_func()->allItemsIgnoreHoverEvents + || !d->scene->d_func()->allItemsUseDefaultCursor)) + || d->transformationAnchor == AnchorUnderMouse + || d->resizeAnchor == AnchorUnderMouse) { widget->setMouseTracking(true); } @@ -3326,7 +3367,8 @@ void QGraphicsView::paintEvent(QPaintEvent *event) #define X11 qt_x11Data #endif backgroundPainter.setCompositionMode(QPainter::CompositionMode_Source); - drawBackground(&backgroundPainter, exposedSceneRect); + QRectF backgroundExposedSceneRect = mapToScene(d->backgroundPixmapExposed.boundingRect()).boundingRect(); + drawBackground(&backgroundPainter, backgroundExposedSceneRect); d->backgroundPixmapExposed = QRegion(); } @@ -3576,6 +3618,10 @@ void QGraphicsView::drawForeground(QPainter *painter, const QRectF &rect) The default implementation calls the scene's drawItems() function. + \obsolete Since Qt 4.6, this function is not called anymore unless + the QGraphicsView::IndirectPainting flag is given as an Optimization + flag. + \sa drawForeground(), drawBackground(), QGraphicsScene::drawItems() */ void QGraphicsView::drawItems(QPainter *painter, int numItems, diff --git a/src/gui/graphicsview/qgraphicsview.h b/src/gui/graphicsview/qgraphicsview.h index 2aed0e6..90576e5 100644 --- a/src/gui/graphicsview/qgraphicsview.h +++ b/src/gui/graphicsview/qgraphicsview.h @@ -278,6 +278,7 @@ private: friend class QGraphicsSceneWidget; friend class QGraphicsScene; friend class QGraphicsScenePrivate; + friend class QGraphicsItemPrivate; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QGraphicsView::CacheMode) diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h index cd161ad..d4b718e 100644 --- a/src/gui/graphicsview/qgraphicsview_p.h +++ b/src/gui/graphicsview/qgraphicsview_p.h @@ -86,6 +86,9 @@ public: qint64 horizontalScroll() const; qint64 verticalScroll() const; + QRectF mapRectToScene(const QRect &rect) const; + QRectF mapRectFromScene(const QRectF &rect) const; + QPointF mousePressItemPoint; QPointF mousePressScenePoint; QPoint mousePressViewPoint; diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index fe569f4..8de81c2 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -1054,7 +1054,7 @@ QVariant QGraphicsWidget::itemChange(GraphicsItemChange change, const QVariant & break; case ItemParentChange: { QGraphicsItem *parent = qVariantValue<QGraphicsItem *>(value); - d->fixFocusChainBeforeReparenting((parent && parent->isWidget()) ? static_cast<QGraphicsWidget *>(parent) : 0); + d->fixFocusChainBeforeReparenting((parent && parent->isWidget()) ? static_cast<QGraphicsWidget *>(parent) : 0, scene()); // Deliver ParentAboutToChange. QEvent event(QEvent::ParentAboutToChange); diff --git a/src/gui/graphicsview/qgraphicswidget_p.cpp b/src/gui/graphicsview/qgraphicswidget_p.cpp index b747a30..5b6490f 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.cpp +++ b/src/gui/graphicsview/qgraphicswidget_p.cpp @@ -743,7 +743,7 @@ bool QGraphicsWidgetPrivate::hasDecoration() const /** * is called after a reparent has taken place to fix up the focus chain(s) */ -void QGraphicsWidgetPrivate::fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *newScene) +void QGraphicsWidgetPrivate::fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *oldScene, QGraphicsScene *newScene) { Q_Q(QGraphicsWidget); @@ -789,7 +789,7 @@ void QGraphicsWidgetPrivate::fixFocusChainBeforeReparenting(QGraphicsWidget *new // update tabFocusFirst for oldScene if the item is going to be removed from oldScene if (newParent) newScene = newParent->scene(); - QGraphicsScene *oldScene = q->scene(); + if (oldScene && newScene != oldScene) oldScene->d_func()->tabFocusFirst = firstOld; diff --git a/src/gui/graphicsview/qgraphicswidget_p.h b/src/gui/graphicsview/qgraphicswidget_p.h index eb53649..65e6962 100644 --- a/src/gui/graphicsview/qgraphicswidget_p.h +++ b/src/gui/graphicsview/qgraphicswidget_p.h @@ -98,7 +98,7 @@ public: mutable qreal *margins; void ensureMargins() const; - void fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *newScene = 0); + void fixFocusChainBeforeReparenting(QGraphicsWidget *newParent, QGraphicsScene *oldScene, QGraphicsScene *newScene = 0); void setLayout_helper(QGraphicsLayout *l); // Layouts diff --git a/src/gui/graphicsview/qgridlayoutengine.cpp b/src/gui/graphicsview/qgridlayoutengine.cpp index f61360a..1fece7a 100644 --- a/src/gui/graphicsview/qgridlayoutengine.cpp +++ b/src/gui/graphicsview/qgridlayoutengine.cpp @@ -51,6 +51,7 @@ #include "qvarlengtharray.h" #include <QtDebug> +#include <QtCore/qmath.h> QT_BEGIN_NAMESPACE @@ -70,7 +71,7 @@ static void insertOrRemoveItems(QVector<T> &items, int index, int delta) static qreal growthFactorBelowPreferredSize(qreal desired, qreal sumAvailable, qreal sumDesired) { Q_ASSERT(sumDesired != 0.0); - return desired * ::pow(sumAvailable / sumDesired, desired / sumDesired); + return desired * qPow(sumAvailable / sumDesired, desired / sumDesired); } static qreal fixedDescent(qreal descent, qreal ascent, qreal targetSize) @@ -181,9 +182,9 @@ void QGridLayoutRowData::distributeMultiCells() QVarLengthArray<qreal> newSizes(span); for (int j = 0; j < NSizes; ++j) { - qreal extra = compare(totalBox, box, j); + qreal extra = compare(box, totalBox, j); if (extra > 0.0) { - calculateGeometries(start, end, totalBox.q_sizes(j), dummy.data(), newSizes.data(), + calculateGeometries(start, end, box.q_sizes(j), dummy.data(), newSizes.data(), 0, totalBox); for (int k = 0; k < span; ++k) diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index ec8dd88..be1190b 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -696,7 +696,9 @@ bool QImageData::checkForAlphaPixels() const /*! \enum QImage::Format - The following image formats are available in all versions of Qt: + The following image formats are available in Qt. Values greater + than QImage::Format_RGB16 were added in Qt 4.4. See the notes + after the table. \value Format_Invalid The image is invalid. \value Format_Mono The image is stored using 1-bit per pixel. Bytes are @@ -705,17 +707,12 @@ bool QImageData::checkForAlphaPixels() const packed with the less significant bit (LSB) first. \value Format_Indexed8 The image is stored using 8-bit indexes - into a colormap. \warning Drawing into a - QImage with Indexed8 format is not - supported. + into a colormap. \value Format_RGB32 The image is stored using a 32-bit RGB format (0xffRRGGBB). \value Format_ARGB32 The image is stored using a 32-bit ARGB - format (0xAARRGGBB). \warning Do not - render into ARGB32 images using - QPainter. Format_ARGB32_Premultiplied is - significantly faster. + format (0xAARRGGBB). \value Format_ARGB32_Premultiplied The image is stored using a premultiplied 32-bit ARGB format (0xAARRGGBB), i.e. the red, @@ -744,6 +741,12 @@ bool QImageData::checkForAlphaPixels() const \value Format_ARGB4444_Premultiplied The image is stored using a premultiplied 16-bit ARGB format (4-4-4-4). + \note Drawing into a QImage with QImage::Format_Indexed8 is not + supported. + + \note Do not render into ARGB32 images using QPainter. Using + QImage::Format_ARGB32_Premultiplied is significantly faster. + \sa format(), convertToFormat() */ diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index d8809ef..ce7f450 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -165,12 +165,16 @@ public: QRect rect() const; int depth() const; +#ifdef QT_DEPRECATED QT_DEPRECATED int numColors() const; +#endif int colorCount() const; QRgb color(int i) const; void setColor(int i, QRgb c); +#ifdef QT_DEPRECATED QT_DEPRECATED void setNumColors(int); +#endif void setColorCount(int); bool allGray() const; @@ -178,7 +182,9 @@ public: uchar *bits(); const uchar *bits() const; +#ifdef QT_DEPRECATED QT_DEPRECATED int numBytes() const; +#endif int byteCount() const; uchar *scanLine(int); diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index 074f3eb..7580446 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -471,7 +471,6 @@ QImageReaderPrivate::QImageReaderPrivate(QImageReader *qq) handler = 0; quality = -1; imageReaderError = QImageReader::UnknownError; - errorString = QLatin1String(QT_TRANSLATE_NOOP(QImageReader, "Unknown error")); q = qq; } @@ -1214,11 +1213,12 @@ bool QImageReader::jumpToImage(int imageNumber) } /*! - For image formats that support animation, this function returns - the number of times the animation should loop. Otherwise, it - returns -1. + For image formats that support animation, this function returns the number + of times the animation should loop. If this function returns -1, it can + either mean the animation should loop forever, or that an error occurred. + If an error occurred, canRead() will return false. - \sa supportsAnimation(), QImageIOHandler::loopCount() + \sa supportsAnimation(), QImageIOHandler::loopCount(), canRead() */ int QImageReader::loopCount() const { @@ -1228,13 +1228,13 @@ int QImageReader::loopCount() const } /*! - For image formats that support animation, this function returns - the total number of images in the animation. + For image formats that support animation, this function returns the total + number of images in the animation. If the format does not support + animation, 0 is returned. - Certain animation formats do not support this feature, in which - case 0 is returned. + This function returns -1 if an error occurred. - \sa supportsAnimation(), QImageIOHandler::imageCount() + \sa supportsAnimation(), QImageIOHandler::imageCount(), canRead() */ int QImageReader::imageCount() const { @@ -1244,11 +1244,13 @@ int QImageReader::imageCount() const } /*! - For image formats that support animation, this function returns - the number of milliseconds to wait until displaying the next frame - in the animation. Otherwise, 0 is returned. + For image formats that support animation, this function returns the number + of milliseconds to wait until displaying the next frame in the animation. + If the image format doesn't support animation, 0 is returned. + + This function returns -1 if an error occurred. - \sa supportsAnimation(), QImageIOHandler::nextImageDelay() + \sa supportsAnimation(), QImageIOHandler::nextImageDelay(), canRead() */ int QImageReader::nextImageDelay() const { @@ -1258,11 +1260,13 @@ int QImageReader::nextImageDelay() const } /*! - For image formats that support animation, this function returns - the sequence number of the current frame. Otherwise, -1 is - returned. + For image formats that support animation, this function returns the + sequence number of the current frame. If the image format doesn't support + animation, 0 is returned. + + This function returns -1 if an error occurred. - \sa supportsAnimation(), QImageIOHandler::currentImageNumber() + \sa supportsAnimation(), QImageIOHandler::currentImageNumber(), canRead() */ int QImageReader::currentImageNumber() const { @@ -1302,6 +1306,8 @@ QImageReader::ImageReaderError QImageReader::error() const */ QString QImageReader::errorString() const { + if (d->errorString.isEmpty()) + return QLatin1String(QT_TRANSLATE_NOOP(QImageReader, "Unknown error")); return d->errorString; } diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 617cfe5..7e4597e 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -831,14 +831,13 @@ bool QPixmap::load(const QString &fileName, const char *format, Qt::ImageConvers if (QPixmapCache::find(key, *this)) return true; - if (!data) - data = QPixmapData::create(0, 0, QPixmapData::PixmapType); - - if (data->fromFile(fileName, format, flags)) { + QPixmapData *tmp = QPixmapData::create(0, 0, QPixmapData::PixmapType); + if (tmp->fromFile(fileName, format, flags)) { + data = tmp; QPixmapCache::insert(key, *this); return true; } - + delete tmp; return false; } diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index d95b4ee..e02b0d6 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -185,7 +185,9 @@ public: const uchar *qwsBits() const; int qwsBytesPerLine() const; QRgb *clut() const; +#ifdef QT_DEPRECATED QT_DEPRECATED int numCols() const; +#endif int colorCount() const; #elif defined(Q_WS_MAC) Qt::HANDLE macQDHandle() const; diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp index 1b01e6f..3c1d7e9 100644 --- a/src/gui/image/qpixmap_raster.cpp +++ b/src/gui/image/qpixmap_raster.cpp @@ -375,7 +375,7 @@ int QRasterPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const case QPaintDevice::PdmWidthMM: return qRound(d->width * 25.4 / qt_defaultDpiX()); case QPaintDevice::PdmHeightMM: - return qRound(d->width * 25.4 / qt_defaultDpiY()); + return qRound(d->height * 25.4 / qt_defaultDpiY()); case QPaintDevice::PdmNumColors: return d->colortable.size(); case QPaintDevice::PdmDepth: diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp index dc33ade..8194db5 100644 --- a/src/gui/image/qpixmap_s60.cpp +++ b/src/gui/image/qpixmap_s60.cpp @@ -235,7 +235,7 @@ static CFbsBitmap* uncompress(CFbsBitmap* bitmap) QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL()); bitmapGc->Activate(bitmapDevice); - bitmapGc->DrawBitmap(TPoint(), bitmap); + bitmapGc->BitBlt(TPoint(), bitmap); delete bitmapGc; delete bitmapDevice; @@ -346,8 +346,6 @@ QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap) QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type), symbianBitmapDataAccess(new QSymbianBitmapDataAccess), cfbsBitmap(0), - bitmapDevice(0), - bitmapGc(0), pengine(0), bytes(0), formatLocked(false) @@ -385,8 +383,6 @@ void QS60PixmapData::resize(int width, int height) if(cfbsBitmap->SizeInPixels() != newSize) { cfbsBitmap->Resize(TSize(width, height)); - bitmapDevice->Resize(TSize(width, height)); - bitmapGc->Resized(); if(pengine) { delete pengine; pengine = 0; @@ -397,21 +393,10 @@ void QS60PixmapData::resize(int width, int height) } } -bool QS60PixmapData::initSymbianBitmapContext() -{ - QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(cfbsBitmap)); - QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL()); - bitmapGc->Activate(bitmapDevice); - - return true; -} - void QS60PixmapData::release() { if (cfbsBitmap) { QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); - delete bitmapGc; - delete bitmapDevice; delete cfbsBitmap; lock.relock(); } @@ -419,8 +404,6 @@ void QS60PixmapData::release() delete pengine; image = QImage(); cfbsBitmap = 0; - bitmapGc = 0; - bitmapDevice = 0; pengine = 0; bytes = 0; } @@ -428,42 +411,52 @@ void QS60PixmapData::release() /*! * Takes ownership of bitmap. Used by window surface */ -void QS60PixmapData::fromSymbianBitmap(CFbsBitmap* bitmap) +void QS60PixmapData::fromSymbianBitmap(CFbsBitmap* bitmap, bool lockFormat) { - cfbsBitmap = bitmap; - formatLocked = true; + Q_ASSERT(bitmap); - if(!initSymbianBitmapContext()) { - qWarning("Could not create CBitmapContext"); - release(); - return; - } + release(); + + cfbsBitmap = bitmap; + formatLocked = lockFormat; - setSerialNumber(cfbsBitmap->Handle()); + setSerialNumber(cfbsBitmap->Handle()); - UPDATE_BUFFER(); + UPDATE_BUFFER(); - // Create default palette if needed - if (cfbsBitmap->DisplayMode() == EGray2) { - image.setColorCount(2); - image.setColor(0, QColor(Qt::color0).rgba()); - image.setColor(1, QColor(Qt::color1).rgba()); + // Create default palette if needed + if (cfbsBitmap->DisplayMode() == EGray2) { + image.setColorCount(2); + image.setColor(0, QColor(Qt::color0).rgba()); + image.setColor(1, QColor(Qt::color1).rgba()); //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid //So invert mono bitmaps so that masks work correctly. image.invertPixels(); - } else if (cfbsBitmap->DisplayMode() == EGray256) { - for (int i=0; i < 256; ++i) - image.setColor(i, qRgb(i, i, i)); - }else if (cfbsBitmap->DisplayMode() == EColor256) { - const TColor256Util *palette = TColor256Util::Default(); - for (int i=0; i < 256; ++i) - image.setColor(i, (QRgb)(palette->Color256(i).Value())); - } + } else if (cfbsBitmap->DisplayMode() == EGray256) { + for (int i=0; i < 256; ++i) + image.setColor(i, qRgb(i, i, i)); + } else if (cfbsBitmap->DisplayMode() == EColor256) { + const TColor256Util *palette = TColor256Util::Default(); + for (int i=0; i < 256; ++i) + image.setColor(i, (QRgb)(palette->Color256(i).Value())); + } +} + +QImage QS60PixmapData::toImage(const QRect &r) const +{ + QS60PixmapData *that = const_cast<QS60PixmapData*>(this); + that->beginDataAccess(); + QImage copy = that->image.copy(r); + that->endDataAccess(); + + return copy; } void QS60PixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags) { + release(); + QImage sourceImage; if (pixelType() == BitmapType) { @@ -517,8 +510,8 @@ void QS60PixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags } cfbsBitmap = createSymbianCFbsBitmap(TSize(sourceImage.width(), sourceImage.height()), mode); - if (!(cfbsBitmap && initSymbianBitmapContext())) { - qWarning("Could not create CFbsBitmap and/or CBitmapContext"); + if (!cfbsBitmap) { + qWarning("Could not create CFbsBitmap"); release(); return; } @@ -544,17 +537,8 @@ void QS60PixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags void QS60PixmapData::copy(const QPixmapData *data, const QRect &rect) { - if (data->pixelType() == BitmapType) { - QBitmap::fromImage(data->toImage().copy(rect)); - return; - } - const QS60PixmapData *s60Data = static_cast<const QS60PixmapData*>(data); - - resize(rect.width(), rect.height()); - cfbsBitmap->SetDisplayMode(s60Data->cfbsBitmap->DisplayMode()); - - bitmapGc->BitBlt(TPoint(0, 0), s60Data->cfbsBitmap, qt_QRect2TRect(rect)); + fromImage(s60Data->toImage(rect), Qt::AutoColor | Qt::OrderedAlphaDither); } bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect) @@ -661,12 +645,7 @@ void QS60PixmapData::setAlphaChannel(const QPixmap &alphaChannel) QImage QS60PixmapData::toImage() const { - QS60PixmapData *that = const_cast<QS60PixmapData*>(this); - that->beginDataAccess(); - QImage copy = that->image.copy(); - that->endDataAccess(); - - return copy; + return toImage(QRect()); } QPaintEngine* QS60PixmapData::paintEngine() const @@ -820,7 +799,9 @@ void* QS60PixmapData::toNativeType(NativeType type) if(displayMode == EGray2) { //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid //So invert mono bitmaps so that masks work correctly. + beginDataAccess(); image.invertPixels(); + endDataAccess(); needsCopy = true; } @@ -828,7 +809,9 @@ void* QS60PixmapData::toNativeType(NativeType type) QImage source; if (convertToArgb32) { + beginDataAccess(); source = image.convertToFormat(QImage::Format_ARGB32); + endDataAccess(); displayMode = EColor16MA; } else { source = image; @@ -858,7 +841,9 @@ void* QS60PixmapData::toNativeType(NativeType type) if(displayMode == EGray2) { // restore pixels + beginDataAccess(); image.invertPixels(); + endDataAccess(); } return reinterpret_cast<void*>(bitmap); diff --git a/src/gui/image/qpixmap_s60_p.h b/src/gui/image/qpixmap_s60_p.h index 8631ebd..2d93622 100644 --- a/src/gui/image/qpixmap_s60_p.h +++ b/src/gui/image/qpixmap_s60_p.h @@ -109,14 +109,12 @@ public: private: void release(); - void fromSymbianBitmap(CFbsBitmap* bitmap); - bool initSymbianBitmapContext(); + void fromSymbianBitmap(CFbsBitmap* bitmap, bool lockFormat=false); + QImage toImage(const QRect &r) const; QSymbianBitmapDataAccess *symbianBitmapDataAccess; CFbsBitmap *cfbsBitmap; - CFbsBitmapDevice *bitmapDevice; - CFbsBitGc *bitmapGc; QPaintEngine *pengine; uchar* bytes; diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp index 7008fbd..f3947ff 100644 --- a/src/gui/image/qpixmap_x11.cpp +++ b/src/gui/image/qpixmap_x11.cpp @@ -1932,6 +1932,8 @@ QPixmap QX11PixmapData::transformed(const QTransform &transform, x11Data->hd = (Qt::HANDLE)XCreatePixmap(X11->display, RootWindow(X11->display, xinfo.screen()), w, h, d); + x11Data->setSerialNumber(++qt_pixmap_serial); + #ifndef QT_NO_XRENDER if (X11->use_xrender) { XRenderPictFormat *format = x11Data->d == 32 diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index b0b7d72..b7b29d7 100644 --- a/src/gui/image/qpixmapcache.cpp +++ b/src/gui/image/qpixmapcache.cpp @@ -424,6 +424,11 @@ QPixmapCache::KeyData* QPMCache::getKeyData(QPixmapCache::Key *key) Q_GLOBAL_STATIC(QPMCache, pm_cache) +int Q_AUTOTEST_EXPORT q_QPixmapCache_keyHashSize() +{ + return pm_cache()->size(); +} + QPixmapCacheEntry::~QPixmapCacheEntry() { pm_cache()->releaseKey(key); diff --git a/src/gui/image/qpixmapfilter.cpp b/src/gui/image/qpixmapfilter.cpp index 3723500..939b86d 100644 --- a/src/gui/image/qpixmapfilter.cpp +++ b/src/gui/image/qpixmapfilter.cpp @@ -52,6 +52,10 @@ #include "private/qgraphicssystem_p.h" #include "private/qpaintengineex_p.h" #include "private/qpaintengine_raster_p.h" +#include "qmath.h" +#include "private/qmath_p.h" +#include "private/qmemrotate_p.h" +#include "private/qdrawhelper_p.h" #ifndef QT_NO_GRAPHICSEFFECT QT_BEGIN_NAMESPACE @@ -585,106 +589,338 @@ QGraphicsBlurEffect::BlurHints QPixmapBlurFilter::blurHints() const return d->hints; } +const qreal radiusScale = qreal(2.5); + /*! \internal */ QRectF QPixmapBlurFilter::boundingRectFor(const QRectF &rect) const { Q_D(const QPixmapBlurFilter); - const qreal delta = d->radius + 1; + const qreal delta = radiusScale * d->radius + 1; return rect.adjusted(-delta, -delta, delta, delta); } -// Blur the image according to the blur radius -// Based on exponential blur algorithm by Jani Huhtanen -// (maximum radius is set to 16) -static QImage blurred(const QImage& image, const QRect& rect, int radius, bool alphaOnly = false) +template <int shift> +inline int qt_static_shift(int value) { - int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 }; - int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1]; + if (shift == 0) + return value; + else if (shift > 0) + return value << (uint(shift) & 0x1f); + else + return value >> (uint(-shift) & 0x1f); +} - QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); - int r1 = rect.top(); - int r2 = rect.bottom(); - int c1 = rect.left(); - int c2 = rect.right(); +template<int aprec, int zprec> +inline void qt_blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, int alpha) +{ + QRgb *pixel = (QRgb *)bptr; + +#define Z_MASK (0xff << zprec) + const int A_zprec = qt_static_shift<zprec - 24>(*pixel) & Z_MASK; + const int R_zprec = qt_static_shift<zprec - 16>(*pixel) & Z_MASK; + const int G_zprec = qt_static_shift<zprec - 8>(*pixel) & Z_MASK; + const int B_zprec = qt_static_shift<zprec>(*pixel) & Z_MASK; +#undef Z_MASK + + const int zR_zprec = zR >> aprec; + const int zG_zprec = zG >> aprec; + const int zB_zprec = zB >> aprec; + const int zA_zprec = zA >> aprec; + + zR += alpha * (R_zprec - zR_zprec); + zG += alpha * (G_zprec - zG_zprec); + zB += alpha * (B_zprec - zB_zprec); + zA += alpha * (A_zprec - zA_zprec); + +#define ZA_MASK (0xff << (zprec + aprec)) + *pixel = + qt_static_shift<24 - zprec - aprec>(zA & ZA_MASK) + | qt_static_shift<16 - zprec - aprec>(zR & ZA_MASK) + | qt_static_shift<8 - zprec - aprec>(zG & ZA_MASK) + | qt_static_shift<-zprec - aprec>(zB & ZA_MASK); +#undef ZA_MASK +} - int bpl = result.bytesPerLine(); - int rgba[4]; - unsigned char* p; +const int alphaIndex = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); - int i1 = 0; - int i2 = 3; +template<int aprec, int zprec> +inline void qt_blurinner_alphaOnly(uchar *bptr, int &z, int alpha) +{ + const int A_zprec = int(*(bptr)) << zprec; + const int z_zprec = z >> aprec; + z += alpha * (A_zprec - z_zprec); + *(bptr) = z >> (zprec + aprec); +} - if (alphaOnly) - i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3); +template<int aprec, int zprec, bool alphaOnly> +inline void qt_blurrow(QImage & im, int line, int alpha) +{ + uchar *bptr = im.scanLine(line); + + int zR = 0, zG = 0, zB = 0, zA = 0; + + if (alphaOnly && im.format() != QImage::Format_Indexed8) + bptr += alphaIndex; + + const int stride = im.depth() >> 3; + const int im_width = im.width(); + for (int index = 0; index < im_width; ++index) { + if (alphaOnly) + qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha); + else + qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha); + bptr += stride; + } + + bptr -= stride; + + for (int index = im_width - 2; index >= 0; --index) { + bptr -= stride; + if (alphaOnly) + qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha); + else + qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha); + } +} + +/* +* expblur(QImage &img, int radius) +* +* Based on exponential blur algorithm by Jani Huhtanen +* +* In-place blur of image 'img' with kernel +* of approximate radius 'radius'. +* +* Blurs with two sided exponential impulse +* response. +* +* aprec = precision of alpha parameter +* in fixed-point format 0.aprec +* +* zprec = precision of state parameters +* zR,zG,zB and zA in fp format 8.zprec +*/ +template <int aprec, int zprec, bool alphaOnly> +void expblur(QImage &img, qreal radius, bool improvedQuality = false, int transposed = 0) +{ + // halve the radius if we're using two passes + if (improvedQuality) + radius *= qreal(0.5); + + Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied + || img.format() == QImage::Format_RGB32); + + // choose the alpha such that pixels at radius distance from a fully + // saturated pixel will have an alpha component of no greater than + // the cutOffIntensity + const qreal cutOffIntensity = 2; + int alpha = radius <= qreal(1e-5) + ? ((1 << aprec)-1) + : qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / radius))); + + int img_height = img.height(); + for (int row = 0; row < img_height; ++row) { + for (int i = 0; i <= improvedQuality; ++i) + qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha); + } + + QImage temp(img.height(), img.width(), img.format()); + if (transposed >= 0) { + if (img.depth() == 8) { + qt_memrotate270(reinterpret_cast<const quint8*>(img.bits()), + img.width(), img.height(), img.bytesPerLine(), + reinterpret_cast<quint8*>(temp.bits()), + temp.bytesPerLine()); + } else { + qt_memrotate270(reinterpret_cast<const quint32*>(img.bits()), + img.width(), img.height(), img.bytesPerLine(), + reinterpret_cast<quint32*>(temp.bits()), + temp.bytesPerLine()); + } + } else { + if (img.depth() == 8) { + qt_memrotate90(reinterpret_cast<const quint8*>(img.bits()), + img.width(), img.height(), img.bytesPerLine(), + reinterpret_cast<quint8*>(temp.bits()), + temp.bytesPerLine()); + } else { + qt_memrotate90(reinterpret_cast<const quint32*>(img.bits()), + img.width(), img.height(), img.bytesPerLine(), + reinterpret_cast<quint32*>(temp.bits()), + temp.bytesPerLine()); + } + } - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r1) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + img_height = temp.height(); + for (int row = 0; row < img_height; ++row) { + for (int i = 0; i <= improvedQuality; ++i) + qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha); + } - p += bpl; - for (int j = r1; j < r2; j++, p += bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + if (transposed == 0) { + qt_memrotate90(reinterpret_cast<const quint32*>(temp.bits()), + temp.width(), temp.height(), temp.bytesPerLine(), + reinterpret_cast<quint32*>(img.bits()), + img.bytesPerLine()); + } else { + img = temp; } +} +#define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) ) +#define AVG16(a,b) ( ((((a)^(b)) & 0xf7deUL) >> 1) + ((a)&(b)) ) - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c1 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; +Q_GUI_EXPORT QImage qt_halfScaled(const QImage &source) +{ + QImage srcImage = source; + + if (source.format() == QImage::Format_Indexed8) { + // assumes grayscale + QImage dest(source.width() / 2, source.height() / 2, srcImage.format()); + + const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits()); + int sx = srcImage.bytesPerLine(); + int sx2 = sx << 1; + + uchar *dst = reinterpret_cast<uchar*>(dest.bits()); + int dx = dest.bytesPerLine(); + int ww = dest.width(); + int hh = dest.height(); + + for (int y = hh; y; --y, dst += dx, src += sx2) { + const uchar *p1 = src; + const uchar *p2 = src + sx; + uchar *q = dst; + for (int x = ww; x; --x, ++q, p1 += 2, p2 += 2) + *q = ((int(p1[0]) + int(p1[1]) + int(p2[0]) + int(p2[1])) + 2) >> 2; + } + + return dest; + } else if (source.format() == QImage::Format_ARGB8565_Premultiplied) { + QImage dest(source.width() / 2, source.height() / 2, srcImage.format()); + + const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits()); + int sx = srcImage.bytesPerLine(); + int sx2 = sx << 1; + + uchar *dst = reinterpret_cast<uchar*>(dest.bits()); + int dx = dest.bytesPerLine(); + int ww = dest.width(); + int hh = dest.height(); + + for (int y = hh; y; --y, dst += dx, src += sx2) { + const uchar *p1 = src; + const uchar *p2 = src + sx; + uchar *q = dst; + for (int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) { + // alpha + q[0] = AVG(AVG(p1[0], p1[3]), AVG(p2[0], p2[3])); + // rgb + const quint16 p16_1 = (p1[2] << 8) | p1[1]; + const quint16 p16_2 = (p1[5] << 8) | p1[4]; + const quint16 p16_3 = (p2[2] << 8) | p2[1]; + const quint16 p16_4 = (p2[5] << 8) | p2[4]; + const quint16 result = AVG16(AVG16(p16_1, p16_2), AVG16(p16_3, p16_4)); + q[1] = result & 0xff; + q[2] = result >> 8; + } + } - p += 4; - for (int j = c1; j < c2; j++, p += 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + return dest; + } else if (source.format() != QImage::Format_ARGB32_Premultiplied + && source.format() != QImage::Format_RGB32) + { + srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied); } - for (int col = c1; col <= c2; col++) { - p = result.scanLine(r2) + col * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + QImage dest(source.width() / 2, source.height() / 2, srcImage.format()); + + const quint32 *src = reinterpret_cast<const quint32*>(const_cast<const QImage &>(srcImage).bits()); + int sx = srcImage.bytesPerLine() >> 2; + int sx2 = sx << 1; + + quint32 *dst = reinterpret_cast<quint32*>(dest.bits()); + int dx = dest.bytesPerLine() >> 2; + int ww = dest.width(); + int hh = dest.height(); - p -= bpl; - for (int j = r1; j < r2; j++, p -= bpl) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; + for (int y = hh; y; --y, dst += dx, src += sx2) { + const quint32 *p1 = src; + const quint32 *p2 = src + sx; + quint32 *q = dst; + for (int x = ww; x; --x, q++, p1 += 2, p2 += 2) + *q = AVG(AVG(p1[0], p1[1]), AVG(p2[0], p2[1])); } - for (int row = r1; row <= r2; row++) { - p = result.scanLine(row) + c2 * 4; - for (int i = i1; i <= i2; i++) - rgba[i] = p[i] << 4; + return dest; +} - p -= 4; - for (int j = c1; j < c2; j++, p -= 4) - for (int i = i1; i <= i2; i++) - p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4; +Q_GUI_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0) +{ + if (blurImage.format() != QImage::Format_ARGB32_Premultiplied + && blurImage.format() != QImage::Format_RGB32) + { + blurImage = blurImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); } - return result; + qreal scale = 1; + if (radius >= 4) { + blurImage = qt_halfScaled(blurImage); + scale = 2; + radius *= qreal(0.5); + } + + if (alphaOnly) + expblur<12, 10, true>(blurImage, radius, quality, transposed); + else + expblur<12, 10, false>(blurImage, radius, quality, transposed); + + if (p) { + p->scale(scale, scale); + p->setRenderHint(QPainter::SmoothPixmapTransform); + p->drawImage(QRect(0, 0, blurImage.width(), blurImage.height()), blurImage); + } +} + +Q_GUI_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0) +{ + if (blurImage.format() == QImage::Format_Indexed8) + expblur<12, 10, true>(blurImage, radius, quality, transposed); + else + expblur<12, 10, false>(blurImage, radius, quality, transposed); } +bool qt_scaleForTransform(const QTransform &transform, qreal *scale); + /*! \internal */ -void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF &srcRect) const +void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF &rect) const { Q_D(const QPixmapBlurFilter); if (!painter->isActive()) return; - if (d->radius <= 0) { + QRectF srcRect = rect; + if (srcRect.isNull()) + srcRect = src.rect(); + + if (d->radius <= 1) { painter->drawPixmap(srcRect.translated(p), src, srcRect); return; } + qreal scaledRadius = radiusScale * d->radius; + qreal scale; + if (qt_scaleForTransform(painter->transform(), &scale)) + scaledRadius /= scale; + QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ? static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0; QPixmapBlurFilter *blurFilter = static_cast<QPixmapBlurFilter*>(filter); if (blurFilter) { - blurFilter->setRadius(d->radius); + blurFilter->setRadius(scaledRadius); blurFilter->setBlurHints(d->hints); blurFilter->draw(painter, p, src, srcRect); return; @@ -693,17 +929,17 @@ void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap QImage srcImage; QImage destImage; - if (srcRect.isNull()) { + if (srcRect == src.rect()) { srcImage = src.toImage(); - destImage = blurred(srcImage, srcImage.rect(), qRound(d->radius)); } else { QRect rect = srcRect.toAlignedRect().intersected(src.rect()); - srcImage = src.copy(rect).toImage(); - destImage = blurred(srcImage, srcImage.rect(), qRound(d->radius)); } - painter->drawImage(p, destImage); + QTransform transform = painter->worldTransform(); + painter->translate(p); + qt_blurImage(painter, srcImage, scaledRadius, (d->hints & QGraphicsBlurEffect::QualityHint), false); + painter->setWorldTransform(transform); } // grayscales the image to dest (could be same). If rect isn't defined @@ -1095,7 +1331,13 @@ void QPixmapDropShadowFilter::draw(QPainter *p, tmpPainter.end(); // blur the alpha channel - tmp = blurred(tmp, tmp.rect(), qRound(d->radius), true); + QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied); + blurred.fill(0); + QPainter blurPainter(&blurred); + qt_blurImage(&blurPainter, tmp, d->radius, false, true); + blurPainter.end(); + + tmp = blurred; // blacken the image... tmpPainter.begin(&tmp); diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 14c863b..1de0f32 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -67,6 +67,9 @@ QT_BEGIN_NAMESPACE # define Q_INTERNAL_WIN_NO_THROW #endif +// avoid going through QImage::scanLine() which calls detach +#define FAST_SCAN_LINE(data, bpl, y) (data + (y) * bpl) + /* All PNG files load to the minimal QImage equivalent. @@ -510,7 +513,7 @@ bool Q_INTERNAL_WIN_NO_THROW QPngHandlerPrivate::readPngImage(QImage *outImage) && outImage->format() == QImage::Format_Indexed8) { int color_table_size = outImage->colorCount(); for (int y=0; y<(int)height; ++y) { - uchar *p = outImage->scanLine(y); + uchar *p = FAST_SCAN_LINE(data, bpl, y); uchar *end = p + width; while (p < end) { if (*p >= color_table_size) diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index 8ec9efb..f2d51f7 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -264,7 +264,7 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy bool gray = format == "pgm"; if (format == "pbm") { - image = image.convertToFormat(QImage::Format_MonoLSB); + image = image.convertToFormat(QImage::Format_Mono); } else if (image.depth() == 1) { image = image.convertToFormat(QImage::Format_Indexed8); } else { diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp index a295d66..1bf7662 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -139,8 +139,7 @@ void QCoeFepInputContext::widgetDestroyed(QWidget *w) // Make sure that the input capabilities of whatever new widget got focused are queried. CCoeControl *ctrl = w->effectiveWinId(); if (ctrl->IsFocused()) { - ctrl->SetFocus(false); - ctrl->SetFocus(true); + queueInputCapabilitiesChanged(); } } diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index de6e6cb..f447989 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -70,6 +70,7 @@ QAbstractItemViewPrivate::QAbstractItemViewPrivate() itemDelegate(0), selectionModel(0), ctrlDragSelectionFlag(QItemSelectionModel::NoUpdate), + noSelectionOnMousePress(false), selectionMode(QAbstractItemView::ExtendedSelection), selectionBehavior(QAbstractItemView::SelectItems), currentlyCommittingEditor(0), @@ -1622,6 +1623,7 @@ void QAbstractItemView::mousePressEvent(QMouseEvent *event) d->pressedIndex = index; d->pressedModifiers = event->modifiers(); QItemSelectionModel::SelectionFlags command = selectionCommand(index, event); + d->noSelectionOnMousePress = command == QItemSelectionModel::NoUpdate || !index.isValid(); QPoint offset = d->offset(); if ((command & QItemSelectionModel::Current) == 0) d->pressedPosition = pos + offset; @@ -1760,9 +1762,10 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event) d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate; - //in the case the user presses on no item we might decide to clear the selection - if (d->selectionModel && !index.isValid()) - d->selectionModel->select(QModelIndex(), selectionCommand(index, event)); + if (d->selectionModel && d->noSelectionOnMousePress) { + d->noSelectionOnMousePress = false; + d->selectionModel->select(index, selectionCommand(index, event)); + } setState(NoState); @@ -2065,9 +2068,13 @@ void QAbstractItemView::focusInEvent(QFocusEvent *event) { Q_D(QAbstractItemView); QAbstractScrollArea::focusInEvent(event); - if (selectionModel() + + const QItemSelectionModel* model = selectionModel(); + const bool currentIndexValid = currentIndex().isValid(); + + if (model && !d->currentIndexSet - && !currentIndex().isValid()) { + && !currentIndexValid) { bool autoScroll = d->autoScroll; d->autoScroll = false; QModelIndex index = moveCursor(MoveNext, Qt::NoModifier); // first visible index @@ -2075,6 +2082,17 @@ void QAbstractItemView::focusInEvent(QFocusEvent *event) selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate); d->autoScroll = autoScroll; } + + if (model && currentIndexValid) { + if (currentIndex().flags() != Qt::ItemIsEditable) + setAttribute(Qt::WA_InputMethodEnabled, false); + else + setAttribute(Qt::WA_InputMethodEnabled); + } + + if (!currentIndexValid) + setAttribute(Qt::WA_InputMethodEnabled, false); + d->viewport->update(); } @@ -2867,6 +2885,8 @@ int QAbstractItemView::sizeHintForRow(int row) const if (row < 0 || row >= d->model->rowCount() || !model()) return -1; + ensurePolished(); + QStyleOptionViewItemV4 option = d->viewOptionsV4(); int height = 0; int colCount = d->model->columnCount(d->root); @@ -2896,6 +2916,8 @@ int QAbstractItemView::sizeHintForColumn(int column) const if (column < 0 || column >= d->model->columnCount() || !model()) return -1; + ensurePolished(); + QStyleOptionViewItemV4 option = d->viewOptionsV4(); int width = 0; int rows = d->model->rowCount(d->root); diff --git a/src/gui/itemviews/qabstractitemview_p.h b/src/gui/itemviews/qabstractitemview_p.h index 0b5cfbe..7fc6780 100644 --- a/src/gui/itemviews/qabstractitemview_p.h +++ b/src/gui/itemviews/qabstractitemview_p.h @@ -347,6 +347,7 @@ public: QMap<int, QPointer<QAbstractItemDelegate> > columnDelegates; QPointer<QItemSelectionModel> selectionModel; QItemSelectionModel::SelectionFlag ctrlDragSelectionFlag; + bool noSelectionOnMousePress; QAbstractItemView::SelectionMode selectionMode; QAbstractItemView::SelectionBehavior selectionBehavior; diff --git a/src/gui/itemviews/qlistwidget.cpp b/src/gui/itemviews/qlistwidget.cpp index 929d688..0ce0e5e 100644 --- a/src/gui/itemviews/qlistwidget.cpp +++ b/src/gui/itemviews/qlistwidget.cpp @@ -173,7 +173,7 @@ void QListModel::move(int srcRow, int dstRow) { if (srcRow == dstRow || srcRow < 0 || srcRow >= items.count() - || dstRow < 0 || dstRow >= items.count()) + || dstRow < 0 || dstRow > items.count()) return; if (!beginMoveRows(QModelIndex(), srcRow, srcRow, QModelIndex(), dstRow)) diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index fc82f30..646a3a1 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -734,6 +734,33 @@ void QSortFilterProxyModelPrivate::source_items_inserted( } } + if (model->rowCount(source_parent) == delta_item_count) { + // Items were inserted where there were none before. + // If it was new rows make sure to create mappings for columns so that a + // valid mapping can be retreived later and vice-versa. + + QVector<int> &orthogonal_proxy_to_source = (orient == Qt::Horizontal) ? m->source_rows : m->source_columns; + QVector<int> &orthogonal_source_to_proxy = (orient == Qt::Horizontal) ? m->proxy_rows : m->proxy_columns; + + if (orthogonal_source_to_proxy.isEmpty()) { + const int ortho_end = (orient == Qt::Horizontal) ? model->rowCount(source_parent) : model->columnCount(source_parent); + + for (int ortho_item = 0; ortho_item < ortho_end; ++ortho_item) { + if ((orient == Qt::Horizontal) ? q->filterAcceptsRow(ortho_item, source_parent) + : q->filterAcceptsColumn(ortho_item, source_parent)) { + orthogonal_proxy_to_source.append(ortho_item); + } + } + orthogonal_source_to_proxy.resize(orthogonal_proxy_to_source.size()); + + if (orient == Qt::Horizontal) { + // We're reacting to columnsInserted, but we've just inserted new rows. Sort them. + sort_source_rows(orthogonal_proxy_to_source, source_parent); + } + build_source_to_proxy_mapping(orthogonal_proxy_to_source, orthogonal_source_to_proxy); + } + } + // Sort and insert the items if (orient == Qt::Vertical) // Only sort rows sort_source_rows(source_items, source_parent); @@ -1171,9 +1198,10 @@ void QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged() { Q_Q(QSortFilterProxyModel); saved_persistent_indexes.clear(); + emit q->layoutAboutToBeChanged(); if (persistent.indexes.isEmpty()) return; - emit q->layoutAboutToBeChanged(); + saved_persistent_indexes = store_persistent_indexes(); } @@ -1181,7 +1209,8 @@ void QSortFilterProxyModelPrivate::_q_sourceLayoutChanged() { Q_Q(QSortFilterProxyModel); if (saved_persistent_indexes.isEmpty()) { - q->invalidate(); + clear_mapping(); + emit q->layoutChanged(); return; } diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp index d27e693..26f5a20 100644 --- a/src/gui/itemviews/qtableview.cpp +++ b/src/gui/itemviews/qtableview.cpp @@ -2359,12 +2359,22 @@ void QTableView::setColumnHidden(int column, bool hide) \property QTableView::sortingEnabled \brief whether sorting is enabled - If this property is true, sorting is enabled for the table; if the - property is false, sorting is not enabled. The default value is false. + If this property is true, sorting is enabled for the table. If + this property is false, sorting is not enabled. The default value + is false. + + \note. Setting the property to true with setSortingEnabled() + immediately triggers a call to sortByColumn() with the current + sort section and order. \sa sortByColumn() */ +/*! + If \a enabled true enables sorting for the table and immediately + trigger a call to sortByColumn() with the current sort section and + order + */ void QTableView::setSortingEnabled(bool enable) { Q_D(QTableView); diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index 3ad9fbb..bcf9cfb 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -2774,6 +2774,7 @@ int QTreeView::sizeHintForColumn(int column) const d->executePostedLayout(); if (d->viewItems.isEmpty()) return -1; + ensurePolished(); int w = 0; QStyleOptionViewItemV4 option = d->viewOptionsV4(); const QVector<QTreeViewItem> viewItems = d->viewItems; diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 8c63968..cdd0c1b 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -2096,7 +2096,11 @@ void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) if (prev) { #ifdef QT_KEYPAD_NAVIGATION if (QApplication::keypadNavigationEnabled()) { - if (prev->hasEditFocus() && reason != Qt::PopupFocusReason) + if (prev->hasEditFocus() && reason != Qt::PopupFocusReason +#ifdef Q_OS_SYMBIAN + && reason != Qt::ActiveWindowFocusReason +#endif + ) prev->setEditFocus(false); } #endif @@ -3629,12 +3633,46 @@ bool QApplication::notify(QObject *receiver, QEvent *e) // walk through parents and check for gestures if (qt_gestureManager) { - if (receiver->isWidgetType()) { - if (qt_gestureManager->filterEvent(static_cast<QWidget *>(receiver), e)) - return true; - } else if (QGesture *gesture = qobject_cast<QGesture *>(receiver)) { - if (qt_gestureManager->filterEvent(gesture, e)) - return true; + switch (e->type()) { + case QEvent::Paint: + case QEvent::MetaCall: + case QEvent::DeferredDelete: + case QEvent::DragEnter: case QEvent::DragMove: case QEvent::DragLeave: + case QEvent::Drop: case QEvent::DragResponse: + case QEvent::ChildAdded: case QEvent::ChildPolished: +#ifdef QT3_SUPPORT + case QEvent::ChildInsertedRequest: + case QEvent::ChildInserted: + case QEvent::LayoutHint: +#endif + case QEvent::ChildRemoved: + case QEvent::UpdateRequest: + case QEvent::UpdateLater: + case QEvent::AccessibilityPrepare: + case QEvent::LocaleChange: + case QEvent::Style: + case QEvent::IconDrag: + case QEvent::StyleChange: + case QEvent::AccessibilityHelp: + case QEvent::AccessibilityDescription: + case QEvent::GraphicsSceneDragEnter: + case QEvent::GraphicsSceneDragMove: + case QEvent::GraphicsSceneDragLeave: + case QEvent::GraphicsSceneDrop: + case QEvent::DynamicPropertyChange: + case QEvent::NetworkReplyUpdated: + break; + default: + if (receiver->isWidgetType()) { + if (qt_gestureManager->filterEvent(static_cast<QWidget *>(receiver), e)) + return true; + } else { + // a special case for events that go to QGesture objects. + // We pass the object to the gesture manager and it'll figure + // out if it's QGesture or not. + if (qt_gestureManager->filterEvent(receiver, e)) + return true; + } } } @@ -5192,6 +5230,8 @@ QInputContext *QApplication::inputContext() const { Q_D(const QApplication); Q_UNUSED(d);// only static members being used. + if (QApplicationPrivate::is_app_closing) + return d->inputContext; #ifdef Q_WS_X11 if (!X11) return 0; diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index ab57c32..27f2644 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -361,6 +361,8 @@ void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop) SetFocusing(true); m_longTapDetector = QLongTapTimer::NewL(this); + + DrawableWindow()->SetPointerGrab(ETrue); } } @@ -472,41 +474,6 @@ void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent) QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent)); } -typedef QPair<QWidget*,QMouseEvent> Event; - -/* - * Helper function called by HandlePointerEvent - separated to keep that function readable - */ -static void generateEnterLeaveEvents(QList<Event> &events, QWidget *widgetUnderPointer, - QPoint globalPos, Qt::MouseButton button, Qt::KeyboardModifiers modifiers) -{ - //moved to another widget, create enter and leave events - if (S60->lastPointerEventTarget) { - QMouseEvent mEventLeave(QEvent::Leave, S60->lastPointerEventTarget->mapFromGlobal( - S60->lastCursorPos), S60->lastCursorPos, button, QApplicationPrivate::mouse_buttons, - modifiers); - events.append(Event(S60->lastPointerEventTarget, mEventLeave)); - } - if (widgetUnderPointer) { - QMouseEvent mEventEnter(QEvent::Enter, widgetUnderPointer->mapFromGlobal(globalPos), - globalPos, button, QApplicationPrivate::mouse_buttons, modifiers); - - events.append(Event(widgetUnderPointer, mEventEnter)); -#ifndef QT_NO_CURSOR - S60->curWin = widgetUnderPointer->effectiveWinId(); - if (!QApplication::overrideCursor()) { -#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS - if (S60->brokenPointerCursors) - qt_symbian_set_pointer_sprite(widgetUnderPointer->cursor()); - else -#endif - qt_symbian_setWindowCursor(widgetUnderPointer->cursor(), S60->curWin); - } -#endif - } -} - - void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) { QMouseEvent::Type type; @@ -514,85 +481,77 @@ void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) mapS60MouseEventTypeToQt(&type, &button, &pEvent); Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers); - if (type == QMouseEvent::None) - return; - - // store events for later sending/saving - QList<Event > events; - QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY); TPoint controlScreenPos = PositionRelativeToScreen(); QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos; + S60->lastCursorPos = globalPos; + S60->lastPointerEventPos = widgetPos; - // widgets interested in the event - QWidget *widgetUnderPointer = qwidget->childAt(widgetPos); - if (!widgetUnderPointer) - widgetUnderPointer = qwidget; //i.e. this container widget + QWidget *mouseGrabber = QWidget::mouseGrabber(); - QWidget *widgetWithMouseGrab = QWidget::mouseGrabber(); + QWidget *popupWidget = qApp->activePopupWidget(); + QWidget *popupReceiver = 0; + if (popupWidget) { + QWidget *popupChild = popupWidget->childAt(popupWidget->mapFromGlobal(globalPos)); + popupReceiver = popupChild ? popupChild : popupWidget; + } - // handle auto grab of pointer when pressing / releasing - if (!widgetWithMouseGrab && type == QEvent::MouseButtonPress) { - //if previously auto-grabbed, generate a fake mouse release (platform bug: mouse release event was lost) - if (S60->mousePressTarget) { - QMouseEvent mEvent(QEvent::MouseButtonRelease, S60->mousePressTarget->mapFromGlobal(globalPos), globalPos, - button, QApplicationPrivate::mouse_buttons, modifiers); - events.append(Event(S60->mousePressTarget,mEvent)); + if (mouseGrabber) { + if (popupReceiver) { + sendMouseEvent(popupReceiver, type, globalPos, button, modifiers); + } else { + sendMouseEvent(mouseGrabber, type, globalPos, button, modifiers); } - //auto grab the mouse - widgetWithMouseGrab = S60->mousePressTarget = widgetUnderPointer; - widgetWithMouseGrab->grabMouse(); - } - if (widgetWithMouseGrab && widgetWithMouseGrab == S60->mousePressTarget && type == QEvent::MouseButtonRelease) { - //release the auto grab - note this release event still goes to the autograb widget - S60->mousePressTarget = 0; - widgetWithMouseGrab->releaseMouse(); + // No Enter/Leave events in grabbing mode. + return; } - QWidget *widgetToReceiveMouseEvent; - if (widgetWithMouseGrab) - widgetToReceiveMouseEvent = widgetWithMouseGrab; - else - widgetToReceiveMouseEvent = widgetUnderPointer; - - //queue QEvent::Enter and QEvent::Leave, if the pointer has moved - if (widgetUnderPointer != S60->lastPointerEventTarget && (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove)) - generateEnterLeaveEvents(events, widgetUnderPointer, globalPos, button, modifiers); + QWidget *widgetUnderPointer = qwidget->childAt(widgetPos); + if (!widgetUnderPointer) + widgetUnderPointer = qwidget; - //save global state - S60->lastCursorPos = globalPos; - S60->lastPointerEventPos = widgetPos; + QApplicationPrivate::dispatchEnterLeave(widgetUnderPointer, S60->lastPointerEventTarget); S60->lastPointerEventTarget = widgetUnderPointer; + QWidget *receiver; + if (!popupReceiver && S60->mousePressTarget && type != QEvent::MouseButtonPress) { + receiver = S60->mousePressTarget; + if (type == QEvent::MouseButtonRelease) + S60->mousePressTarget = 0; + } else { + receiver = popupReceiver ? popupReceiver : widgetUnderPointer; + if (type == QEvent::MouseButtonPress) + S60->mousePressTarget = receiver; + } + #if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS) if (S60->brokenPointerCursors) qt_symbian_move_cursor_sprite(); #endif - //queue this event. - Q_ASSERT(widgetToReceiveMouseEvent); - QMouseEvent mEvent(type, widgetToReceiveMouseEvent->mapFromGlobal(globalPos), globalPos, + sendMouseEvent(receiver, type, globalPos, button, modifiers); +} + +void QSymbianControl::sendMouseEvent( + QWidget *receiver, + QEvent::Type type, + const QPoint &globalPos, + Qt::MouseButton button, + Qt::KeyboardModifiers modifiers) +{ + Q_ASSERT(receiver); + QMouseEvent mEvent(type, receiver->mapFromGlobal(globalPos), globalPos, button, QApplicationPrivate::mouse_buttons, modifiers); - events.append(Event(widgetToReceiveMouseEvent,mEvent)); QEventDispatcherS60 *dispatcher; // It is theoretically possible for someone to install a different event dispatcher. - if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(widgetToReceiveMouseEvent->d_func()->threadData->eventDispatcher)) != 0) { + if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(receiver->d_func()->threadData->eventDispatcher)) != 0) { if (dispatcher->excludeUserInputEvents()) { - for (int i=0;i < events.count();++i) - { - Event next = events[i]; - dispatcher->saveInputEvent(this, next.first, new QMouseEvent(next.second)); - } + dispatcher->saveInputEvent(this, receiver, new QMouseEvent(mEvent)); return; } } - //send events in the queue - for (int i=0;i < events.count();++i) - { - Event next = events[i]; - sendMouseEvent(next.first, &(next.second)); - } + sendMouseEvent(receiver, &mEvent); } bool QSymbianControl::sendMouseEvent(QWidget *widget, QMouseEvent *mEvent) @@ -672,27 +631,58 @@ TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCod fakeEvent.iType = TPointerEvent::EButton1Up; S60->virtualMouseAccel = 1; S60->virtualMouseLastKey = 0; + switch (keyCode) { + case Qt::Key_Left: + S60->virtualMousePressedKeys &= ~QS60Data::Left; + break; + case Qt::Key_Right: + S60->virtualMousePressedKeys &= ~QS60Data::Right; + break; + case Qt::Key_Up: + S60->virtualMousePressedKeys &= ~QS60Data::Up; + break; + case Qt::Key_Down: + S60->virtualMousePressedKeys &= ~QS60Data::Down; + break; + case Qt::Key_Select: + S60->virtualMousePressedKeys &= ~QS60Data::Select; + break; + } } else if (type == EEventKey) { switch (keyCode) { case Qt::Key_Left: + S60->virtualMousePressedKeys |= QS60Data::Left; x -= S60->virtualMouseAccel; fakeEvent.iType = TPointerEvent::EMove; break; case Qt::Key_Right: + S60->virtualMousePressedKeys |= QS60Data::Right; x += S60->virtualMouseAccel; fakeEvent.iType = TPointerEvent::EMove; break; case Qt::Key_Up: + S60->virtualMousePressedKeys |= QS60Data::Up; y -= S60->virtualMouseAccel; fakeEvent.iType = TPointerEvent::EMove; break; case Qt::Key_Down: + S60->virtualMousePressedKeys |= QS60Data::Down; y += S60->virtualMouseAccel; fakeEvent.iType = TPointerEvent::EMove; break; case Qt::Key_Select: - fakeEvent.iType = TPointerEvent::EButton1Down; + // Platform bug. If you start pressing several keys simultaneously (for + // example for drag'n'drop), Symbian starts producing spurious up and + // down messages for some keys. Therefore, make sure we have a clean slate + // of pressed keys before starting a new button press. + if (S60->virtualMousePressedKeys != 0) { + S60->virtualMousePressedKeys |= QS60Data::Select; + return EKeyWasConsumed; + } else { + S60->virtualMousePressedKeys |= QS60Data::Select; + fakeEvent.iType = TPointerEvent::EButton1Down; + } break; } } diff --git a/src/gui/kernel/qboxlayout.cpp b/src/gui/kernel/qboxlayout.cpp index d965933..fd16861 100644 --- a/src/gui/kernel/qboxlayout.cpp +++ b/src/gui/kernel/qboxlayout.cpp @@ -830,9 +830,11 @@ void QBoxLayout::setGeometry(const QRect &r) if (d->hasHfw && !horz(d->dir)) { for (int i = 0; i < n; i++) { QBoxLayoutItem *box = d->list.at(i); - if (box->item->hasHeightForWidth()) + if (box->item->hasHeightForWidth()) { + int width = qBound(box->item->minimumSize().width(), s.width(), box->item->maximumSize().width()); a[i].sizeHint = a[i].minimumSize = - box->item->heightForWidth(s.width()); + box->item->heightForWidth(width); + } } } diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index ddd8ca6..3352dbd 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -349,7 +349,9 @@ extern "C" { // since we accepted the drag enter event, the widget expects // future drage move events. // ### check if we need to treat this like the drag enter event. - nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDEEvent.dropAction()); + nsActions = NSDragOperationNone; + // Save as ignored in the answer rect. + qDMEvent.setDropAction(Qt::IgnoreAction); } else { nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDMEvent.dropAction()); } @@ -357,7 +359,6 @@ extern "C" { return nsActions; } } - - (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender { NSPoint windowPoint = [sender draggingLocation]; @@ -402,13 +403,15 @@ extern "C" { qDMEvent.setDropAction(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction); qDMEvent.accept(); QApplication::sendEvent(qwidget, &qDMEvent); - qt_mac_copy_answer_rect(qDMEvent); NSDragOperation operation = qt_mac_mapDropAction(qDMEvent.dropAction()); if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) { // ignore this event (we will still receive further notifications) operation = NSDragOperationNone; + // Save as ignored in the answer rect. + qDMEvent.setDropAction(Qt::IgnoreAction); } + qt_mac_copy_answer_rect(qDMEvent); return operation; } @@ -777,7 +780,7 @@ extern "C" { NSPoint windowPoint = [theEvent locationInWindow]; NSPoint globalPoint = [[theEvent window] convertBaseToScreen:windowPoint]; NSPoint localPoint = [self convertPoint:windowPoint fromView:nil]; - QPoint qlocal = QPoint(localPoint.x, flipYCoordinate(localPoint.y)); + QPoint qlocal = QPoint(localPoint.x, localPoint.y); QPoint qglobal = QPoint(globalPoint.x, flipYCoordinate(globalPoint.y)); Qt::MouseButtons buttons = QApplication::mouseButtons(); bool wheelOK = false; diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index c4a25e1..eedf0a7 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -409,7 +409,7 @@ QMouseEventEx::~QMouseEventEx() consider a top-level window A containing a child B which in turn contains a child C (all with mouse tracking enabled): - \image hoverEvents.png + \image hoverevents.png Now, if you move the cursor from the top to the bottom in the middle of A, you will get the following QEvent::MouseMove events: @@ -432,7 +432,7 @@ QMouseEventEx::~QMouseEventEx() \o A::HoverMove, B::HoverMove \o A::HoverMove, B::HoverMove, C::HoverMove \endlist - + */ /*! @@ -3023,7 +3023,7 @@ QShowEvent::~QShowEvent() This event is only used to notify the application of a request. It may be safely ignored. - \note This class is currently supported for Mac Os X only. + \note This class is currently supported for Mac OS X only. */ /*! @@ -3066,6 +3066,8 @@ QFileOpenEvent::~QFileOpenEvent() \fn QUrl QFileOpenEvent::url() const Returns the url that is being opened. + + \since 4.6 */ QUrl QFileOpenEvent::url() const { diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp index 192f9ac..d7cbebd 100644 --- a/src/gui/kernel/qgesturemanager.cpp +++ b/src/gui/kernel/qgesturemanager.cpp @@ -187,10 +187,8 @@ QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recogni #endif } - QList<QGesture *> states = - m_objectGestures.value(QGestureManager::ObjectGesture(object, type)); // check if the QGesture for this recognizer has already been created - foreach (QGesture *state, states) { + foreach (QGesture *state, m_objectGestures.value(QGestureManager::ObjectGesture(object, type))) { if (m_gestureToRecognizer.value(state) == recognizer) return state; } @@ -215,14 +213,13 @@ QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recogni return state; } -bool QGestureManager::filterEventThroughContexts(const QMultiHash<QObject *, +bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *, Qt::GestureType> &contexts, QEvent *event) { QSet<QGesture *> triggeredGestures; QSet<QGesture *> finishedGestures; QSet<QGesture *> newMaybeGestures; - QSet<QGesture *> canceledGestures; QSet<QGesture *> notGestures; // TODO: sort contexts by the gesture type and check if one of the contexts @@ -231,7 +228,7 @@ bool QGestureManager::filterEventThroughContexts(const QMultiHash<QObject *, bool ret = false; // filter the event through recognizers - typedef QHash<QObject *, Qt::GestureType>::const_iterator ContextIterator; + typedef QMultiMap<QObject *, Qt::GestureType>::const_iterator ContextIterator; for (ContextIterator cit = contexts.begin(), ce = contexts.end(); cit != ce; ++cit) { Qt::GestureType gestureType = cit.value(); QMap<Qt::GestureType, QGestureRecognizer *>::const_iterator @@ -271,6 +268,9 @@ bool QGestureManager::filterEventThroughContexts(const QMultiHash<QObject *, } } } + if (triggeredGestures.isEmpty() && finishedGestures.isEmpty() + && newMaybeGestures.isEmpty() && notGestures.isEmpty()) + return ret; QSet<QGesture *> startedGestures = triggeredGestures - m_activeGestures; triggeredGestures &= m_activeGestures; @@ -280,8 +280,7 @@ bool QGestureManager::filterEventThroughContexts(const QMultiHash<QObject *, // check if a running gesture switched back to not gesture state, // i.e. were canceled - QSet<QGesture *> activeToCancelGestures = m_activeGestures & notGestures; - canceledGestures += activeToCancelGestures; + QSet<QGesture *> canceledGestures = m_activeGestures & notGestures; // start timers for new gestures in maybe state foreach (QGesture *state, newMaybeGestures) { @@ -449,14 +448,14 @@ void QGestureManager::cleanupGesturesForRemovedRecognizer(QGesture *gesture) // return true if accepted (consumed) bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) { - QSet<Qt::GestureType> types; - QMultiHash<QObject *, Qt::GestureType> contexts; + QMap<Qt::GestureType, int> types; + QMultiMap<QObject *, Qt::GestureType> contexts; QWidget *w = receiver; typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator; if (!w->d_func()->gestureContext.isEmpty()) { for(ContextIterator it = w->d_func()->gestureContext.begin(), e = w->d_func()->gestureContext.end(); it != e; ++it) { - types.insert(it.key()); + types.insert(it.key(), 0); contexts.insertMulti(w, it.key()); } } @@ -468,7 +467,7 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) e = w->d_func()->gestureContext.end(); it != e; ++it) { if (!(it.value() & Qt::DontStartGestureOnChildren)) { if (!types.contains(it.key())) { - types.insert(it.key()); + types.insert(it.key(), 0); contexts.insertMulti(w, it.key()); } } @@ -477,20 +476,20 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) break; w = w->parentWidget(); } - return filterEventThroughContexts(contexts, event); + return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event); } #ifndef QT_NO_GRAPHICSVIEW bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event) { - QSet<Qt::GestureType> types; - QMultiHash<QObject *, Qt::GestureType> contexts; + QMap<Qt::GestureType, int> types; + QMultiMap<QObject *, Qt::GestureType> contexts; QGraphicsObject *item = receiver; if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) { typedef QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator ContextIterator; for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { - types.insert(it.key()); + types.insert(it.key(), 0); contexts.insertMulti(item, it.key()); } } @@ -503,20 +502,23 @@ bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event) e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { if (!(it.value() & Qt::DontStartGestureOnChildren)) { if (!types.contains(it.key())) { - types.insert(it.key()); + types.insert(it.key(), 0); contexts.insertMulti(item, it.key()); } } } item = item->parentObject(); } - return filterEventThroughContexts(contexts, event); + return contexts.isEmpty() ? false : filterEventThroughContexts(contexts, event); } #endif -bool QGestureManager::filterEvent(QGesture *state, QEvent *event) +bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) { - QMultiHash<QObject *, Qt::GestureType> contexts; + if (!m_gestureToRecognizer.contains(static_cast<QGesture *>(receiver))) + return false; + QGesture *state = static_cast<QGesture *>(receiver); + QMultiMap<QObject *, Qt::GestureType> contexts; contexts.insert(state, state->gestureType()); return filterEventThroughContexts(contexts, event); } diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h index 4efa10b..5329d1d 100644 --- a/src/gui/kernel/qgesturemanager_p.h +++ b/src/gui/kernel/qgesturemanager_p.h @@ -73,7 +73,7 @@ public: void unregisterGestureRecognizer(Qt::GestureType type); bool filterEvent(QWidget *receiver, QEvent *event); - bool filterEvent(QGesture *receiver, QEvent *event); + bool filterEvent(QObject *receiver, QEvent *event); #ifndef QT_NO_GRAPHICSVIEW bool filterEvent(QGraphicsObject *receiver, QEvent *event); #endif //QT_NO_GRAPHICSVIEW @@ -86,7 +86,7 @@ public: protected: void timerEvent(QTimerEvent *event); - bool filterEventThroughContexts(const QMultiHash<QObject *, Qt::GestureType> &contexts, + bool filterEventThroughContexts(const QMultiMap<QObject *, Qt::GestureType> &contexts, QEvent *event); private: diff --git a/src/gui/kernel/qguieventdispatcher_glib.cpp b/src/gui/kernel/qguieventdispatcher_glib.cpp index f8a638c..a252499 100644 --- a/src/gui/kernel/qguieventdispatcher_glib.cpp +++ b/src/gui/kernel/qguieventdispatcher_glib.cpp @@ -152,6 +152,8 @@ static gboolean x11EventSourceDispatch(GSource *s, GSourceFunc callback, gpointe out: + source->d->runTimersOnceWithNormalPriority(); + if (callback) callback(user_data); return true; diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index 08f8bb5..737e9d7 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -103,6 +103,14 @@ public: int defaultDpiY; WId curWin; int virtualMouseLastKey; + enum PressedKeys { + Select = 0x1, + Right = 0x2, + Down = 0x4, + Left = 0x8, + Up = 0x10 + }; + int virtualMousePressedKeys; // of the above type, but avoids casting problems int virtualMouseAccel; int virtualMouseMaxAccel; #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS @@ -192,6 +200,12 @@ private: TKeyResponse OfferKeyEvent(const TKeyEvent& aKeyEvent,TEventCode aType); TKeyResponse sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent); bool sendMouseEvent(QWidget *widget, QMouseEvent *mEvent); + void sendMouseEvent( + QWidget *receiver, + QEvent::Type type, + const QPoint &globalPos, + Qt::MouseButton button, + Qt::KeyboardModifiers modifiers); void HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ); #ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER void translateAdvancedPointerEvent(const TAdvancedPointerEvent *event); diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index e551a1d..5c4cc74 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -9774,13 +9774,12 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f) } #endif - if (newParent) { - if (QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore()) { + if (QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore()) { + if (newParent) oldBs->removeDirtyWidget(this); - // Move the widget and all its static children from - // the old backing store to the new one. - oldBs->moveStaticWidgets(this); - } + // Move the widget and all its static children from + // the old backing store to the new one. + oldBs->moveStaticWidgets(this); } if ((QApplicationPrivate::app_compile_version < 0x040200 @@ -11872,16 +11871,20 @@ void QWidget::ungrabGesture(Qt::GestureType gesture) mouse when a mouse button is pressed and keeps it until the last button is released. - Note that only visible widgets can grab mouse input. If - isVisible() returns false for a widget, that widget cannot call - grabMouse(). + \note Only visible widgets can grab mouse input. If isVisible() + returns false for a widget, that widget cannot call grabMouse(). + + \note \bold{(Mac OS X developers)} For \e Cocoa, calling + grabMouse() on a widget only works when the mouse is inside the + frame of that widget. For \e Carbon, it works outside the widget's + frame as well, like for Windows and X11. \sa releaseMouse() grabKeyboard() releaseKeyboard() */ /*! \fn void QWidget::grabMouse(const QCursor &cursor) - \overload + \overload grabMouse() Grabs the mouse input and changes the cursor shape. @@ -11891,6 +11894,8 @@ void QWidget::ungrabGesture(Qt::GestureType gesture) \warning Grabbing the mouse might lock the terminal. + \note \bold{(Mac OS X developers)} See the note in QWidget::grabMouse(). + \sa releaseMouse(), grabKeyboard(), releaseKeyboard(), setCursor() */ diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 7dc4d85..69f1353 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -3671,6 +3671,7 @@ void QWidgetPrivate::raise_sys() return; #if QT_MAC_USE_COCOA + QMacCocoaAutoReleasePool pool; if (isRealWindow()) { // Calling orderFront shows the window on Cocoa too. if (!q->testAttribute(Qt::WA_DontShowOnScreen) && q->isVisible()) { @@ -4493,10 +4494,14 @@ void QWidgetPrivate::createTLSysExtra() void QWidgetPrivate::deleteTLSysExtra() { #ifndef QT_MAC_USE_COCOA - if(extra->topextra->group) { + if (extra->topextra->group) { qt_mac_release_window_group(extra->topextra->group); extra->topextra->group = 0; } + if (extra->topextra->windowIcon) { + ReleaseIconRef(extra->topextra->windowIcon); + extra->topextra->windowIcon = 0; + } #endif } diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp index 0bc9cbc..f9db485 100644 --- a/src/gui/kernel/qwidget_x11.cpp +++ b/src/gui/kernel/qwidget_x11.cpp @@ -1084,7 +1084,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows) } else { // release previous focus information participating with // preedit preservation of qic - QInputContext *qic = inputContext(); + QInputContext *qic = QApplicationPrivate::inputContext; if (qic) qic->widgetDestroyed(this); } diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 628a109..a6cc9c7 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -379,6 +379,13 @@ symbian { QMAKE_CXXFLAGS.ARMCC *= -O3 } +neon { + DEFINES += QT_HAVE_NEON + HEADERS += painting/qdrawhelper_neon_p.h + SOURCES += painting/qdrawhelper_neon.cpp + QMAKE_CXXFLAGS *= -mfpu=neon +} + contains(QT_CONFIG, zlib) { INCLUDEPATH += ../3rdparty/zlib } else:!contains(QT_CONFIG, no-zlib) { diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp index a6b4cef..f626494 100644 --- a/src/gui/painting/qbezier.cpp +++ b/src/gui/painting/qbezier.cpp @@ -497,7 +497,7 @@ static bool addCircle(const QBezier *b, qreal offset, QBezier *o) cos_a = 1.; if (cos_a < -1.) cos_a = -1; - angles[i] = acos(cos_a)/Q_PI; + angles[i] = qAcos(cos_a)/Q_PI; } if (angles[0] + angles[1] > 1.) { @@ -816,17 +816,17 @@ bool QBezier::findIntersections(const QBezier &a, const QBezier &b, QVector<QPair<qreal, qreal> > *t) { if (IntersectBB(a, b)) { - QPointF la1(fabs((a.x3 - a.x2) - (a.x2 - a.x1)), - fabs((a.y3 - a.y2) - (a.y2 - a.y1))); - QPointF la2(fabs((a.x4 - a.x3) - (a.x3 - a.x2)), - fabs((a.y4 - a.y3) - (a.y3 - a.y2))); + QPointF la1(qFabs((a.x3 - a.x2) - (a.x2 - a.x1)), + qFabs((a.y3 - a.y2) - (a.y2 - a.y1))); + QPointF la2(qFabs((a.x4 - a.x3) - (a.x3 - a.x2)), + qFabs((a.y4 - a.y3) - (a.y3 - a.y2))); QPointF la; if (la1.x() > la2.x()) la.setX(la1.x()); else la.setX(la2.x()); if (la1.y() > la2.y()) la.setY(la1.y()); else la.setY(la2.y()); - QPointF lb1(fabs((b.x3 - b.x2) - (b.x2 - b.x1)), - fabs((b.y3 - b.y2) - (b.y2 - b.y1))); - QPointF lb2(fabs((b.x4 - b.x3) - (b.x3 - b.x2)), - fabs((b.y4 - b.y3) - (b.y3 - b.y2))); + QPointF lb1(qFabs((b.x3 - b.x2) - (b.x2 - b.x1)), + qFabs((b.y3 - b.y2) - (b.y2 - b.y1))); + QPointF lb2(qFabs((b.x4 - b.x3) - (b.x3 - b.x2)), + qFabs((b.y4 - b.y3) - (b.y3 - b.y2))); QPointF lb; if (lb1.x() > lb2.x()) lb.setX(lb1.x()); else lb.setX(lb2.x()); if (lb1.y() > lb2.y()) lb.setY(lb1.y()); else lb.setY(lb2.y()); @@ -1120,7 +1120,7 @@ static inline void bindInflectionPoint(const QBezier &bez, const qreal t, qreal ey = 3 * (right.y2 - right.y3); qreal s4 = qAbs(6 * (ey * ax - ex * ay) / qSqrt(ex * ex + ey * ey)) + 0.00001f; - qreal tf = pow(qreal(9 * flatness / s4), qreal(1./3.)); + qreal tf = qPow(qreal(9 * flatness / s4), qreal(1./3.)); *tMinus = t - (1 - t) * tf; *tPlus = t + (1 - t) * tf; } diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h index 7dbd0c2..c284871 100644 --- a/src/gui/painting/qbezier_p.h +++ b/src/gui/painting/qbezier_p.h @@ -166,8 +166,6 @@ inline void QBezier::coefficients(qreal t, qreal &a, qreal &b, qreal &c, qreal & inline QPointF QBezier::pointAt(qreal t) const { - Q_ASSERT(t >= 0); - Q_ASSERT(t <= 1); #if 1 qreal a, b, c, d; coefficients(t, a, b, c, d); diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index 1d15dac..81d1515 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -605,7 +605,7 @@ static void qt_blend_argb32_on_argb32(uchar *destPixels, int dbpl, } -static void qt_blend_rgb32_on_rgb32(uchar *destPixels, int dbpl, +void qt_blend_rgb32_on_rgb32(uchar *destPixels, int dbpl, const uchar *srcPixels, int sbpl, int w, int h, int const_alpha) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 4df7f8a..9bb4486 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -44,6 +44,7 @@ #include <private/qpainter_p.h> #include <private/qdrawhelper_x86_p.h> #include <private/qdrawhelper_armv6_p.h> +#include <private/qdrawhelper_neon_p.h> #include <private/qmath_p.h> #include <qmath.h> @@ -1182,7 +1183,7 @@ static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operato rx -= data->gradient.conical.center.x; ry -= data->gradient.conical.center.y; while (buffer < end) { - qreal angle = atan2(ry, rx) + data->gradient.conical.angle; + qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle; *buffer = qt_gradient_pixel(&data->gradient, 1 - angle / (2*Q_PI)); @@ -1196,7 +1197,7 @@ static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operato if (!rw) rw = 1; while (buffer < end) { - qreal angle = atan2(ry/rw - data->gradient.conical.center.x, + qreal angle = qAtan2(ry/rw - data->gradient.conical.center.x, rx/rw - data->gradient.conical.center.y) + data->gradient.conical.angle; @@ -1363,7 +1364,10 @@ static void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int le for (int i = 0; i < length; ++i) { PRELOAD_COND2(dest, src) uint s = src[i]; - dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); + if (s >= 0xff000000) + dest[i] = s; + else if (s != 0) + dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); } } else { for (int i = 0; i < length; ++i) { @@ -7140,17 +7144,17 @@ void qt_build_pow_tables() { } #else for (int i=0; i<256; ++i) { - qt_pow_rgb_gamma[i] = uchar(qRound(pow(i / qreal(255.0), smoothing) * 255)); - qt_pow_rgb_invgamma[i] = uchar(qRound(pow(i / qreal(255.), 1 / smoothing) * 255)); + qt_pow_rgb_gamma[i] = uchar(qRound(qPow(i / qreal(255.0), smoothing) * 255)); + qt_pow_rgb_invgamma[i] = uchar(qRound(qPow(i / qreal(255.), 1 / smoothing) * 255)); } #endif #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) const qreal gray_gamma = 2.31; for (int i=0; i<256; ++i) - qt_pow_gamma[i] = uint(qRound(pow(i / qreal(255.), gray_gamma) * 2047)); + qt_pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047)); for (int i=0; i<2048; ++i) - qt_pow_invgamma[i] = uchar(qRound(pow(i / 2047.0, 1 / gray_gamma) * 255)); + qt_pow_invgamma[i] = uchar(qRound(qPow(i / 2047.0, 1 / gray_gamma) * 255)); #endif } @@ -7725,7 +7729,8 @@ enum CPUFeatures { SSE = 0x10, SSE2 = 0x20, CMOV = 0x40, - IWMMXT = 0x80 + IWMMXT = 0x80, + NEON = 0x100 }; static uint detectCPUFeatures() @@ -7751,6 +7756,9 @@ static uint detectCPUFeatures() // runtime detection only available when running as a previlegied process static const bool doIWMMXT = !qgetenv("QT_NO_IWMMXT").toInt(); return doIWMMXT ? IWMMXT : 0; +#elif defined(QT_HAVE_NEON) + static const bool doNEON = !qgetenv("QT_NO_NEON").toInt(); + return doNEON ? NEON : 0; #else uint features = 0; #if defined(__x86_64__) || defined(Q_OS_WIN64) @@ -8122,7 +8130,14 @@ void qInitDrawhelperAsm() qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_armv6; qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_armv6; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_armv6; -#endif // Q_CC_RVCT && QT_HAVE_ARMV6 +#elif defined(QT_HAVE_NEON) + if (features & NEON) { + qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_neon; + qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_neon; + } +#endif if (functionForModeSolidAsm) { const int destinationMode = QPainter::CompositionMode_Destination; diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp new file mode 100644 index 0000000..7fe11bf --- /dev/null +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qdrawhelper_p.h> + +#ifdef QT_HAVE_NEON + +#include <private/qdrawhelper_neon_p.h> +#include <arm_neon.h> + +QT_BEGIN_NAMESPACE + +static inline int16x8_t qvdiv_255_s16(int16x8_t x, int16x8_t half) +{ + // result = (x + (x >> 8) + 0x80) >> 8 + + const int16x8_t temp = vshrq_n_s16(x, 8); // x >> 8 + const int16x8_t sum_part = vaddq_s16(x, half); // x + 0x80 + const int16x8_t sum = vaddq_s16(temp, sum_part); + + return vreinterpretq_s16_u16(vshrq_n_u16(vreinterpretq_u16_s16(sum), 8)); +} + +static inline int16x8_t qvbyte_mul_s16(int16x8_t x, int16x8_t alpha, int16x8_t half) +{ + // t = qRound(x * alpha / 255.0) + + const int16x8_t t = vmulq_s16(x, alpha); // t + return qvdiv_255_s16(t, half); +} + +static inline int16x8_t qvinterpolate_pixel_255(int16x8_t x, int16x8_t a, int16x8_t y, int16x8_t b, int16x8_t half) +{ + // t = x * a + y * b + + const int16x8_t ta = vmulq_s16(x, a); + const int16x8_t tb = vmulq_s16(y, b); + + return qvdiv_255_s16(vaddq_s16(ta, tb), half); +} + +static inline int16x8_t qvsource_over_s16(int16x8_t src16, int16x8_t dst16, int16x8_t half, int16x8_t full) +{ + const int16x4_t alpha16_high = vdup_lane_s16(vget_high_s16(src16), 3); + const int16x4_t alpha16_low = vdup_lane_s16(vget_low_s16(src16), 3); + + const int16x8_t alpha16 = vsubq_s16(full, vcombine_s16(alpha16_low, alpha16_high)); + + return vaddq_s16(src16, qvbyte_mul_s16(dst16, alpha16, half)); +} + +void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) +{ + const uint *src = (const uint *) srcPixels; + uint *dst = (uint *) destPixels; + int16x8_t half = vdupq_n_s16(0x80); + int16x8_t full = vdupq_n_s16(0xff); + if (const_alpha == 256) { + for (int y = 0; y < h; ++y) { + int x = 0; + for (; x < w-3; x += 4) { + int32x4_t src32 = vld1q_s32((int32_t *)&src[x]); + if ((src[x] & src[x+1] & src[x+2] & src[x+3]) >= 0xff000000) { + // all opaque + vst1q_s32((int32_t *)&dst[x], src32); + } else if (src[x] | src[x+1] | src[x+2] | src[x+3]) { + int32x4_t dst32 = vld1q_s32((int32_t *)&dst[x]); + + const uint8x16_t src8 = vreinterpretq_u8_s32(src32); + const uint8x16_t dst8 = vreinterpretq_u8_s32(dst32); + + const uint8x8_t src8_low = vget_low_u8(src8); + const uint8x8_t dst8_low = vget_low_u8(dst8); + + const uint8x8_t src8_high = vget_high_u8(src8); + const uint8x8_t dst8_high = vget_high_u8(dst8); + + const int16x8_t src16_low = vreinterpretq_s16_u16(vmovl_u8(src8_low)); + const int16x8_t dst16_low = vreinterpretq_s16_u16(vmovl_u8(dst8_low)); + + const int16x8_t src16_high = vreinterpretq_s16_u16(vmovl_u8(src8_high)); + const int16x8_t dst16_high = vreinterpretq_s16_u16(vmovl_u8(dst8_high)); + + const int16x8_t result16_low = qvsource_over_s16(src16_low, dst16_low, half, full); + const int16x8_t result16_high = qvsource_over_s16(src16_high, dst16_high, half, full); + + const int32x2_t result32_low = vreinterpret_s32_s8(vmovn_s16(result16_low)); + const int32x2_t result32_high = vreinterpret_s32_s8(vmovn_s16(result16_high)); + + vst1q_s32((int32_t *)&dst[x], vcombine_s32(result32_low, result32_high)); + } + } + for (; x<w; ++x) { + uint s = src[x]; + if (s >= 0xff000000) + dst[x] = s; + else if (s != 0) + dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s)); + } + dst = (quint32 *)(((uchar *) dst) + dbpl); + src = (const quint32 *)(((const uchar *) src) + sbpl); + } + } else if (const_alpha != 0) { + const_alpha = (const_alpha * 255) >> 8; + int16x8_t const_alpha16 = vdupq_n_s16(const_alpha); + for (int y = 0; y < h; ++y) { + int x = 0; + for (; x < w-3; x += 4) { + if (src[x] | src[x+1] | src[x+2] | src[x+3]) { + int32x4_t src32 = vld1q_s32((int32_t *)&src[x]); + int32x4_t dst32 = vld1q_s32((int32_t *)&dst[x]); + + const uint8x16_t src8 = vreinterpretq_u8_s32(src32); + const uint8x16_t dst8 = vreinterpretq_u8_s32(dst32); + + const uint8x8_t src8_low = vget_low_u8(src8); + const uint8x8_t dst8_low = vget_low_u8(dst8); + + const uint8x8_t src8_high = vget_high_u8(src8); + const uint8x8_t dst8_high = vget_high_u8(dst8); + + const int16x8_t src16_low = vreinterpretq_s16_u16(vmovl_u8(src8_low)); + const int16x8_t dst16_low = vreinterpretq_s16_u16(vmovl_u8(dst8_low)); + + const int16x8_t src16_high = vreinterpretq_s16_u16(vmovl_u8(src8_high)); + const int16x8_t dst16_high = vreinterpretq_s16_u16(vmovl_u8(dst8_high)); + + const int16x8_t srcalpha16_low = qvbyte_mul_s16(src16_low, const_alpha16, half); + const int16x8_t srcalpha16_high = qvbyte_mul_s16(src16_high, const_alpha16, half); + + const int16x8_t result16_low = qvsource_over_s16(srcalpha16_low, dst16_low, half, full); + const int16x8_t result16_high = qvsource_over_s16(srcalpha16_high, dst16_high, half, full); + + const int32x2_t result32_low = vreinterpret_s32_s8(vmovn_s16(result16_low)); + const int32x2_t result32_high = vreinterpret_s32_s8(vmovn_s16(result16_high)); + + vst1q_s32((int32_t *)&dst[x], vcombine_s32(result32_low, result32_high)); + } + } + for (; x<w; ++x) { + uint s = src[x]; + if (s != 0) { + s = BYTE_MUL(s, const_alpha); + dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s)); + } + } + dst = (quint32 *)(((uchar *) dst) + dbpl); + src = (const quint32 *)(((const uchar *) src) + sbpl); + } + } +} + +// qblendfunctions.cpp +void qt_blend_rgb32_on_rgb32(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + +void qt_blend_rgb32_on_rgb32_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) +{ + if (const_alpha != 256) { + if (const_alpha != 0) { + const uint *src = (const uint *) srcPixels; + uint *dst = (uint *) destPixels; + int16x8_t half = vdupq_n_s16(0x80); + const_alpha = (const_alpha * 255) >> 8; + int one_minus_const_alpha = 255 - const_alpha; + int16x8_t const_alpha16 = vdupq_n_s16(const_alpha); + int16x8_t one_minus_const_alpha16 = vdupq_n_s16(255 - const_alpha); + for (int y = 0; y < h; ++y) { + int x = 0; + for (; x < w-3; x += 4) { + int32x4_t src32 = vld1q_s32((int32_t *)&src[x]); + int32x4_t dst32 = vld1q_s32((int32_t *)&dst[x]); + + const uint8x16_t src8 = vreinterpretq_u8_s32(src32); + const uint8x16_t dst8 = vreinterpretq_u8_s32(dst32); + + const uint8x8_t src8_low = vget_low_u8(src8); + const uint8x8_t dst8_low = vget_low_u8(dst8); + + const uint8x8_t src8_high = vget_high_u8(src8); + const uint8x8_t dst8_high = vget_high_u8(dst8); + + const int16x8_t src16_low = vreinterpretq_s16_u16(vmovl_u8(src8_low)); + const int16x8_t dst16_low = vreinterpretq_s16_u16(vmovl_u8(dst8_low)); + + const int16x8_t src16_high = vreinterpretq_s16_u16(vmovl_u8(src8_high)); + const int16x8_t dst16_high = vreinterpretq_s16_u16(vmovl_u8(dst8_high)); + + const int16x8_t result16_low = qvinterpolate_pixel_255(src16_low, const_alpha16, dst16_low, one_minus_const_alpha16, half); + const int16x8_t result16_high = qvinterpolate_pixel_255(src16_high, const_alpha16, dst16_high, one_minus_const_alpha16, half); + + const int32x2_t result32_low = vreinterpret_s32_s8(vmovn_s16(result16_low)); + const int32x2_t result32_high = vreinterpret_s32_s8(vmovn_s16(result16_high)); + + vst1q_s32((int32_t *)&dst[x], vcombine_s32(result32_low, result32_high)); + } + for (; x<w; ++x) { + uint s = src[x]; + s = BYTE_MUL(s, const_alpha); + dst[x] = INTERPOLATE_PIXEL_255(src[x], const_alpha, dst[x], one_minus_const_alpha); + } + dst = (quint32 *)(((uchar *) dst) + dbpl); + src = (const quint32 *)(((const uchar *) src) + sbpl); + } + } + } else { + qt_blend_rgb32_on_rgb32(destPixels, dbpl, srcPixels, sbpl, w, h, const_alpha); + } +} + +QT_END_NAMESPACE + +#endif // QT_HAVE_NEON + diff --git a/src/gui/painting/qdrawhelper_neon_p.h b/src/gui/painting/qdrawhelper_neon_p.h new file mode 100644 index 0000000..cb9a0d6 --- /dev/null +++ b/src/gui/painting/qdrawhelper_neon_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDRAWHELPER_NEON_P_H +#define QDRAWHELPER_NEON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qdrawhelper_p.h> + +QT_BEGIN_NAMESPACE + +#ifdef QT_HAVE_NEON + +void qt_blend_argb32_on_argb32_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + +void qt_blend_rgb32_on_rgb32_neon(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + +#endif // QT_HAVE_NEON + +QT_END_NAMESPACE + +#endif // QDRAWHELPER_NEON_P_H diff --git a/src/gui/painting/qmatrix.h b/src/gui/painting/qmatrix.h index 152b3c9..af48bcb 100644 --- a/src/gui/painting/qmatrix.h +++ b/src/gui/painting/qmatrix.h @@ -102,7 +102,9 @@ public: bool isInvertible() const { return !qFuzzyIsNull(_m11*_m22 - _m12*_m21); } qreal determinant() const { return _m11*_m22 - _m12*_m21; } +#ifdef QT_DEPRECATED QT_DEPRECATED qreal det() const { return _m11*_m22 - _m12*_m21; } +#endif QMatrix inverted(bool *invertible = 0) const; diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp index 67dc2c7..e3a6f78 100644 --- a/src/gui/painting/qmemrotate.cpp +++ b/src/gui/painting/qmemrotate.cpp @@ -572,5 +572,26 @@ QT_IMPL_MEMROTATE(quint32, qrgb_generic16) QT_IMPL_MEMROTATE(quint16, qrgb_generic16) #endif +struct qrgb_gl_rgba +{ +public: + inline qrgb_gl_rgba(quint32 v) { + if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) + data = ((v << 16) & 0xff0000) | ((v >> 16) & 0xff) | (v & 0xff00ff00); + else + data = (v << 8) | ((v >> 24) & 0xff); + } + + inline operator quint32() const { return data; } + +private: + quint32 data; +} Q_PACKED; + +void Q_GUI_EXPORT qt_memrotate90_gl(const quint32 *src, int srcWidth, int srcHeight, int srcStride, + quint32 *dest, int dstStride) +{ + qt_memrotate90_template(src, srcWidth, srcHeight, srcStride, reinterpret_cast<qrgb_gl_rgba *>(dest), dstStride); +} QT_END_NAMESPACE diff --git a/src/gui/painting/qmemrotate_p.h b/src/gui/painting/qmemrotate_p.h index 676a880..8aee575 100644 --- a/src/gui/painting/qmemrotate_p.h +++ b/src/gui/painting/qmemrotate_p.h @@ -81,6 +81,8 @@ QT_BEGIN_NAMESPACE void Q_GUI_QWS_EXPORT qt_memrotate180(const srctype*, int, int, int, desttype*, int); \ void Q_GUI_QWS_EXPORT qt_memrotate270(const srctype*, int, int, int, desttype*, int) +void Q_GUI_EXPORT qt_memrotate90(const quint32*, int, int, int, quint32*, int); + QT_DECL_MEMROTATE(quint32, quint32); QT_DECL_MEMROTATE(quint32, quint16); QT_DECL_MEMROTATE(quint16, quint32); diff --git a/src/gui/painting/qpaintdevice.h b/src/gui/painting/qpaintdevice.h index 9148e4b..0f8191e 100644 --- a/src/gui/painting/qpaintdevice.h +++ b/src/gui/painting/qpaintdevice.h @@ -96,7 +96,9 @@ public: int logicalDpiY() const { return metric(PdmDpiY); } int physicalDpiX() const { return metric(PdmPhysicalDpiX); } int physicalDpiY() const { return metric(PdmPhysicalDpiY); } +#ifdef QT_DEPRECATED QT_DEPRECATED int numColors() const { return metric(PdmNumColors); } +#endif int colorCount() const { return metric(PdmNumColors); } int depth() const { return metric(PdmDepth); } diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 4a72434..aa3b89e 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3018,10 +3018,10 @@ void QRasterPaintEngine::drawCachedGlyphs(const QPointF &p, const QTextItemInt & QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) : d->glyphCacheType; QImageTextureGlyphCache *cache = - (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(glyphType, s->matrix); + (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(0, glyphType, s->matrix); if (!cache) { cache = new QImageTextureGlyphCache(glyphType, s->matrix); - ti.fontEngine->setGlyphCache(glyphType, cache); + ti.fontEngine->setGlyphCache(0, cache); } cache->populate(ti, glyphs, positions); diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 66bf4f7..fd67f96 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -1317,6 +1317,90 @@ void QPainterPrivate::updateState(QPainterState *newState) Another workaround is to convert the paths to polygons first and then draw the polygons instead. + \section1 Performance + + QPainter is a rich framework that allows developers to do a great + variety of graphical operations, such as gradients, composition + modes and vector graphics. And QPainter can do this across a + variety of different hardware and software stacks. Naturally the + underlying combination of hardware and software has some + implications for performance, and ensuring that every single + operation is fast in combination with all the various combinations + of composition modes, brushes, clipping, transformation, etc, is + close to an impossible task because of the number of + permutations. As a compromise we have selected a subset of the + QPainter API and backends, where performance is guaranteed to be as + good as we can sensibly get it for the given combination of + hardware and software. + + The backends we focus on as high-performance engines are: + + \list + + \o Raster - This backend implements all rendering in pure software + and is always used to render into QImages. For optimal performance + only use the format types QImage::Format_ARGB32_Premultiplied, + QImage::Format_RGB32 or QImage::Format_RGB16. Any other format, + including QImage::Format_ARGB32, has significantly worse + performance. This engine is also used by default on Windows and on + QWS. It can be used as default graphics system on any + OS/hardware/software combination by passing \c {-graphicssystem + raster} on the command line + + \o OpenGL 2.0 (ES) - This backend is the primary backend for + hardware accelerated graphics. It can be run on desktop machines + and embedded devices supporting the OpenGL 2.0 or OpenGL/ES 2.0 + specification. This includes most graphics chips produced in the + last couple of years. The engine can be enabled by using QPainter + onto a QGLWidget or by passing \c {-graphicssystem opengl} on the + command line when the underlying system supports it. + + \o OpenVG - This backend implements the Khronos standard for 2D + and Vector Graphics. It is primarily for embedded devices with + hardware support for OpenVG. The engine can be enabled by + passing \c {-graphicssystem openvg} on the command line when + the underlying system supports it. + + \endlist + + These operations are: + + \list + + \o Simple transformations, meaning translation and scaling, pluss + 0, 90, 180, 270 degree rotations. + + \o \c drawPixmap() in combination with simple transformations and + opacity with non-smooth transformation mode + (\c QPainter::SmoothPixmapTransform not enabled as a render hint). + + \o Text drawing with regular font sizes with simple + transformations with solid colors using no or 8-bit antialiasing. + + \o Rectangle fills with solid color, two-color linear gradients + and simple transforms. + + \o Rectangular clipping with simple transformations and intersect + clip. + + \o Composition Modes \c QPainter::CompositionMode_Source and + QPainter::CompositionMode_SourceOver + + \o Rounded rectangle filling using solid color and two-color + linear gradients fills. + + \o 3x3 patched pixmaps, via qDrawBorderPixmap. + + \endlist + + This list gives an indication of which features to safely use in + an application where performance is critical. For certain setups, + other operations may be fast too, but before making extensive use + of them, it is recommended to benchmark and verify them on the + system where the software will run in the end. There are also + cases where expensive operations are ok to use, for instance when + the result is cached in a QPixmap. + \sa QPaintDevice, QPaintEngine, {QtSvg Module}, {Basic Drawing Example}, {Drawing Utility Functions} */ diff --git a/src/gui/painting/qpathclipper.cpp b/src/gui/painting/qpathclipper.cpp index 51d6195..a41ab6d 100644 --- a/src/gui/painting/qpathclipper.cpp +++ b/src/gui/painting/qpathclipper.cpp @@ -1209,7 +1209,7 @@ static qreal computeAngle(const QPointF &v) } #else // doesn't seem to be robust enough - return atan2(v.x(), v.y()) + Q_PI; + return qAtan2(v.x(), v.y()) + Q_PI; #endif } diff --git a/src/gui/painting/qprinterinfo_unix.cpp b/src/gui/painting/qprinterinfo_unix.cpp index 6684ff7..930785b 100644 --- a/src/gui/painting/qprinterinfo_unix.cpp +++ b/src/gui/painting/qprinterinfo_unix.cpp @@ -75,7 +75,9 @@ private: QString m_name; bool m_isNull; bool m_default; - QList<QPrinter::PaperSize> m_paperSizes; + mutable bool m_mustGetPaperSizes; + mutable QList<QPrinter::PaperSize> m_paperSizes; + int m_cupsPrinterIndex; QPrinterInfo* q_ptr; }; @@ -838,16 +840,7 @@ QList<QPrinterInfo> QPrinterInfo::availablePrinters() list.append(QPrinterInfo(printerName)); if (cupsPrinters[i].is_default) list[i].d_ptr->m_default = true; - // Find paper sizes. - cups.setCurrentPrinter(i); - const ppd_option_t* sizes = cups.pageSizes(); - if (sizes) { - for (int j = 0; j < sizes->num_choices; ++j) { - list[i].d_ptr->m_paperSizes.append( - QPrinterInfoPrivate::string2PaperSize( - QLatin1String(sizes->choices[j].choice))); - } - } + list[i].d_ptr->m_cupsPrinterIndex = i; } } else { #endif @@ -909,16 +902,7 @@ QPrinterInfo::QPrinterInfo(const QPrinter& printer) if (printerName == printer.printerName()) { if (cupsPrinters[i].is_default) d->m_default = true; - // Find paper sizes. - cups.setCurrentPrinter(i); - const ppd_option_t* sizes = cups.pageSizes(); - if (sizes) { - for (int j = 0; j < sizes->num_choices; ++j) { - d->m_paperSizes.append( - QPrinterInfoPrivate::string2PaperSize( - QLatin1String(sizes->choices[j].choice))); - } - } + d->m_cupsPrinterIndex = i; return; } } @@ -983,6 +967,26 @@ bool QPrinterInfo::isDefault() const QList< QPrinter::PaperSize> QPrinterInfo::supportedPaperSizes() const { const Q_D(QPrinterInfo); + if (d->m_mustGetPaperSizes) { + d->m_mustGetPaperSizes = false; + +#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY) + QCUPSSupport cups; + if (QCUPSSupport::isAvailable()) { + // Find paper sizes from CUPS. + cups.setCurrentPrinter(d->m_cupsPrinterIndex); + const ppd_option_t* sizes = cups.pageSizes(); + if (sizes) { + for (int j = 0; j < sizes->num_choices; ++j) { + d->m_paperSizes.append( + QPrinterInfoPrivate::string2PaperSize( + QLatin1String(sizes->choices[j].choice))); + } + } + } +#endif + + } return d->m_paperSizes; } @@ -993,6 +997,8 @@ QPrinterInfoPrivate::QPrinterInfoPrivate() { m_isNull = true; m_default = false; + m_mustGetPaperSizes = true; + m_cupsPrinterIndex = 0; q_ptr = 0; } @@ -1001,6 +1007,8 @@ QPrinterInfoPrivate::QPrinterInfoPrivate(const QString& name) m_name = name; m_isNull = false; m_default = false; + m_mustGetPaperSizes = true; + m_cupsPrinterIndex = 0; q_ptr = 0; } diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h index 2a1be86..f99fbf6 100644 --- a/src/gui/painting/qregion.h +++ b/src/gui/painting/qregion.h @@ -116,7 +116,9 @@ public: QRect boundingRect() const; QVector<QRect> rects() const; void setRects(const QRect *rect, int num); +#ifdef QT_DEPRECATED QT_DEPRECATED int numRects() const; +#endif int rectCount() const; const QRegion operator|(const QRegion &r) const; diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp index 228a6b1..8bb4728 100644 --- a/src/gui/painting/qstroker.cpp +++ b/src/gui/painting/qstroker.cpp @@ -910,8 +910,8 @@ QPointF qt_curves_for_arc(const QRectF &rect, qreal startAngle, qreal sweepLengt } } - int startSegment = int(floor(startAngle / 90)); - int endSegment = int(floor((startAngle + sweepLength) / 90)); + int startSegment = int(qFloor(startAngle / 90)); + int endSegment = int(qFloor((startAngle + sweepLength) / 90)); qreal startT = (startAngle - startSegment * 90) / 90; qreal endT = (startAngle + sweepLength - endSegment * 90) / 90; diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h index 57473d1..bb0c630 100644 --- a/src/gui/painting/qtextureglyphcache_p.h +++ b/src/gui/painting/qtextureglyphcache_p.h @@ -76,7 +76,7 @@ class Q_GUI_EXPORT QTextureGlyphCache : public QFontEngineGlyphCache { public: QTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix) - : QFontEngineGlyphCache(matrix), m_w(0), m_h(0), m_cx(0), m_cy(0), m_type(type) { } + : QFontEngineGlyphCache(matrix, type), m_w(0), m_h(0), m_cx(0), m_cy(0) { } virtual ~QTextureGlyphCache() { } @@ -98,8 +98,6 @@ public: virtual void resizeTextureData(int width, int height) = 0; virtual int glyphMargin() const { return 0; } - QFontEngineGlyphCache::Type cacheType() const { return m_type; } - virtual void fillTexture(const Coord &coord, glyph_t glyph) = 0; inline void createCache(int width, int height) { @@ -121,7 +119,6 @@ protected: int m_h; // image height int m_cx; // current x int m_cy; // current y - QFontEngineGlyphCache::Type m_type; }; diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp index c66da71..15427c6 100644 --- a/src/gui/painting/qwindowsurface_s60.cpp +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -68,12 +68,14 @@ QS60WindowSurface::QS60WindowSurface(QWidget* widget) mode = EColor16MA; // Try for transparency anyway // We create empty CFbsBitmap here -> it will be resized in setGeometry - CFbsBitmap *bitmap = q_check_ptr(new CFbsBitmap); // CBase derived object needs check on new + CFbsBitmap *bitmap = q_check_ptr(new CFbsBitmap); // CBase derived object needs check on new qt_symbian_throwIfError( bitmap->Create( TSize(0, 0), mode ) ); QS60PixmapData *data = new QS60PixmapData(QPixmapData::PixmapType); - data->fromSymbianBitmap(bitmap); - d_ptr->device = QPixmap(data); + if (data) { + data->fromSymbianBitmap(bitmap, true); + d_ptr->device = QPixmap(data); + } setStaticContentsSupport(true); } diff --git a/src/gui/statemachine/qguistatemachine.cpp b/src/gui/statemachine/qguistatemachine.cpp index 4f7806f..c3a9228 100644 --- a/src/gui/statemachine/qguistatemachine.cpp +++ b/src/gui/statemachine/qguistatemachine.cpp @@ -186,8 +186,10 @@ static QEvent *cloneEvent(QEvent *e) case QEvent::DeactivateControl: return new QEvent(*e); +#ifndef QT_NO_CONTEXTMENU case QEvent::ContextMenu: return new QContextMenuEvent(*static_cast<QContextMenuEvent*>(e)); +#endif case QEvent::InputMethod: return new QInputMethodEvent(*static_cast<QInputMethodEvent*>(e)); case QEvent::AccessibilityPrepare: diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index 5028e5f..c1beb6a 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -2775,7 +2775,7 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt, QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize; int w = size.width(); int h = size.height(); - int midHeight = static_cast<int>(ceil(float(tr.height() - h) / 2)); + int midHeight = static_cast<int>(qCeil(float(tr.height() - h) / 2)); int midWidth = ((tr.width() - w) / 2); bool atTheTop = true; diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index be4f15a..bcc993a 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -84,23 +84,15 @@ extern Q_GUI_EXPORT int qt_defaultDpiY(); const QS60StylePrivate::SkinElementFlags QS60StylePrivate::KDefaultSkinElementFlags = SkinElementFlags(SF_PointNorth | SF_StateEnabled); -static const QByteArray propertyKeyLayouts = "layouts"; -static const QByteArray propertyKeyCurrentlayout = "currentlayout"; - static const qreal goldenRatio = 1.618; const layoutHeader QS60StylePrivate::m_layoutHeaders[] = { // *** generated layout data *** -{240,320,1,15,true,"QVGA Landscape Mirrored"}, -{240,320,1,15,false,"QVGA Landscape"}, -{320,240,1,15,true,"QVGA Portrait Mirrored"}, -{320,240,1,15,false,"QVGA Portrait"}, -{360,640,1,15,true,"NHD Landscape Mirrored"}, -{360,640,1,15,false,"NHD Landscape"}, -{640,360,1,15,true,"NHD Portrait Mirrored"}, -{640,360,1,15,false,"NHD Portrait"}, -{352,800,1,12,true,"E90 Landscape Mirrored"}, -{352,800,1,12,false,"E90 Landscape"} +{240,320,1,15,"QVGA Landscape"}, +{320,240,1,15,"QVGA Portrait"}, +{360,640,1,15,"NHD Landscape"}, +{640,360,1,15,"NHD Portrait"}, +{352,800,1,12,"E90 Landscape"} // *** End of generated data *** }; const int QS60StylePrivate::m_numberOfLayouts = @@ -108,15 +100,10 @@ const int QS60StylePrivate::m_numberOfLayouts = const short QS60StylePrivate::data[][MAX_PIXELMETRICS] = { // *** generated pixel metrics *** -{5,0,-909,0,0,2,0,0,-1,7,12,19,13,13,6,200,-909,-909,-909,20,13,2,0,0,21,7,18,-909,3,3,1,-909,-909,0,1,0,0,12,20,15,15,18,18,1,115,18,0,-909,-909,-909,-909,0,0,16,2,-909,0,0,-909,16,-909,-909,-909,-909,32,18,55,24,55,3,3,4,9,13,-909,5,51,11,5,0,6,3,3,8,3,3,-909,2,-909,-909,-909,-909,5,5,3,1}, {5,0,-909,0,0,2,0,0,-1,7,12,19,13,13,6,200,-909,-909,-909,20,13,2,0,0,21,7,18,-909,3,3,1,-909,-909,0,1,0,0,12,20,15,15,18,18,1,115,18,0,-909,-909,-909,-909,0,0,16,2,-909,0,0,-909,16,-909,-909,-909,-909,32,18,55,24,55,3,3,4,9,13,-909,5,51,11,5,0,3,3,6,8,3,3,-909,2,-909,-909,-909,-909,5,5,3,1}, -{5,0,-909,0,0,1,0,0,-1,8,14,22,15,15,7,164,-909,-909,-909,19,15,2,0,0,21,8,27,-909,4,4,1,-909,-909,0,7,6,0,13,23,17,17,21,21,7,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,65,27,65,4,4,5,10,15,-909,5,58,13,5,0,7,4,4,9,4,4,-909,2,-909,-909,-909,-909,6,6,3,1}, {5,0,-909,0,0,1,0,0,-1,8,14,22,15,15,7,164,-909,-909,-909,19,15,2,0,0,21,8,27,-909,4,4,1,-909,-909,0,7,6,0,13,23,17,17,21,21,7,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,65,27,65,4,4,5,10,15,-909,5,58,13,5,0,4,4,7,9,4,4,-909,2,-909,-909,-909,-909,6,6,3,1}, -{7,0,-909,0,0,2,0,0,-1,25,69,28,19,19,9,258,-909,-909,-909,23,19,26,0,0,32,25,72,-909,5,5,2,-909,-909,0,7,21,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,25,2,-909,0,0,-909,25,-909,-909,-909,-909,87,27,77,35,77,5,5,6,8,19,-909,7,74,19,7,0,8,5,5,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1}, {7,0,-909,0,0,2,0,0,-1,25,69,28,19,19,9,258,-909,-909,-909,23,19,26,0,0,32,25,72,-909,5,5,2,-909,-909,0,7,21,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,25,2,-909,0,0,-909,25,-909,-909,-909,-909,87,27,77,35,77,5,5,6,8,19,-909,7,74,19,7,0,5,5,8,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1}, -{7,0,-909,0,0,2,0,0,-1,25,68,28,19,19,9,258,-909,-909,-909,31,19,6,0,0,32,25,60,-909,5,5,2,-909,-909,0,7,32,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,26,2,-909,0,0,-909,26,-909,-909,-909,-909,87,27,96,35,96,5,5,6,8,19,-909,7,74,22,7,0,8,5,5,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1}, {7,0,-909,0,0,2,0,0,-1,25,68,28,19,19,9,258,-909,-909,-909,31,19,6,0,0,32,25,60,-909,5,5,2,-909,-909,0,7,32,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,26,2,-909,0,0,-909,26,-909,-909,-909,-909,87,27,96,35,96,5,5,6,8,19,-909,7,74,22,7,0,5,5,8,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1}, -{7,0,-909,0,0,2,0,0,-1,10,20,27,18,18,9,301,-909,-909,-909,29,18,5,0,0,35,7,32,-909,5,5,2,-909,-909,0,2,8,0,16,28,21,21,26,26,2,170,26,0,-909,-909,-909,-909,0,0,21,5,-909,0,0,-909,-909,-909,-909,-909,-909,54,26,265,34,265,5,5,6,3,18,-909,7,72,19,7,0,8,6,5,11,6,5,-909,2,-909,-909,-909,-909,5,5,3,1}, {7,0,-909,0,0,2,0,0,-1,10,20,27,18,18,9,301,-909,-909,-909,29,18,5,0,0,35,7,32,-909,5,5,2,-909,-909,0,2,8,0,16,28,21,21,26,26,2,170,26,0,-909,-909,-909,-909,0,0,21,6,-909,0,0,-909,-909,-909,-909,-909,-909,54,26,265,34,265,5,5,6,3,18,-909,7,72,19,7,0,5,6,8,11,6,5,-909,2,-909,-909,-909,-909,5,5,3,1} // *** End of generated data *** }; @@ -203,10 +190,24 @@ void QS60StylePrivate::drawSkinElement(SkinElements element, QPainter *painter, QS60StyleEnums::SP_QsnCpScrollHandleBottom, Qt::Vertical, painter, rect, flags | SF_PointNorth); break; case SE_SliderHandleHorizontal: - drawPart(QS60StyleEnums::SP_QgnIndiSliderEdit, painter, rect, flags | SF_PointNorth); + drawPart(QS60StyleEnums::SP_QgnGrafNsliderMarker, painter, rect, flags | SF_PointNorth); break; case SE_SliderHandleVertical: - drawPart(QS60StyleEnums::SP_QgnIndiSliderEdit, painter, rect, flags | SF_PointEast); + drawPart(QS60StyleEnums::SP_QgnGrafNsliderMarker, painter, rect, flags | SF_PointEast); + break; + case SE_SliderHandleSelectedHorizontal: + drawPart(QS60StyleEnums::SP_QgnGrafNsliderMarkerSelected, painter, rect, flags | SF_PointNorth); + break; + case SE_SliderHandleSelectedVertical: + drawPart(QS60StyleEnums::SP_QgnGrafNsliderMarkerSelected, painter, rect, flags | SF_PointEast); + break; + case SE_SliderGrooveVertical: + drawRow(QS60StyleEnums::SP_QgnGrafNsliderEndLeft, QS60StyleEnums::SP_QgnGrafNsliderMiddle, + QS60StyleEnums::SP_QgnGrafNsliderEndRight, Qt::Vertical, painter, rect, flags | SF_PointEast); + break; + case SE_SliderGrooveHorizontal: + drawRow(QS60StyleEnums::SP_QgnGrafNsliderEndLeft, QS60StyleEnums::SP_QgnGrafNsliderMiddle, + QS60StyleEnums::SP_QgnGrafNsliderEndRight, Qt::Horizontal, painter, rect, flags | SF_PointNorth); break; case SE_TabBarTabEastActive: drawRow(QS60StyleEnums::SP_QgnGrafTabActiveL, QS60StyleEnums::SP_QgnGrafTabActiveM, @@ -309,8 +310,8 @@ QColor QS60StylePrivate::stateColor(const QColor &color, const QStyleOption *opt QColor hsvColor = retColor.toHsv(); int colorSat = hsvColor.saturation(); int colorVal = hsvColor.value(); - colorSat = (colorSat!=0) ? (colorSat>>1) : 128; - colorVal = (colorVal!=0) ? (colorVal>>1) : 128; + colorSat = (colorSat != 0) ? (colorSat >> 1) : 128; + colorVal = (colorVal != 0) ? (colorVal >> 1) : 128; hsvColor.setHsv(hsvColor.hue(), colorSat, colorVal); retColor = hsvColor.toRgb(); } @@ -338,7 +339,7 @@ QColor QS60StylePrivate::lighterColor(const QColor &baseColor) bool QS60StylePrivate::drawsOwnThemeBackground(const QWidget *widget) { - return qobject_cast<const QDialog *> (widget); + return (widget ? (widget->windowType() == Qt::Dialog) : false); } QFont QS60StylePrivate::s60Font( @@ -371,7 +372,6 @@ void QS60StylePrivate::clearCaches(CacheClearReason reason) case CC_LayoutChange: // when layout changes, the colors remain in cache, but graphics and fonts can change m_mappedFontsCache.clear(); - deleteBackground(); QPixmapCache::clear(); break; case CC_ThemeChange: @@ -399,10 +399,10 @@ QColor QS60StylePrivate::colorFromFrameGraphics(SkinFrameElements frame) const if (!cachedColorExists) { const int frameCornerWidth = pixelMetric(PM_Custom_FrameCornerWidth); const int frameCornerHeight = pixelMetric(PM_Custom_FrameCornerHeight); - Q_ASSERT(2*frameCornerWidth<32); - Q_ASSERT(2*frameCornerHeight<32); + Q_ASSERT(2 * frameCornerWidth < 32); + Q_ASSERT(2 * frameCornerHeight < 32); - const QImage frameImage = QS60StylePrivate::frame(frame, QSize(32,32)).toImage(); + const QImage frameImage = QS60StylePrivate::frame(frame, QSize(32, 32)).toImage(); Q_ASSERT(frameImage.bytesPerLine() > 0); if (frameImage.isNull()) return Qt::black; @@ -417,14 +417,14 @@ QColor QS60StylePrivate::colorFromFrameGraphics(SkinFrameElements frame) const int skips = 0; int estimations = 0; - const int topBorderLastPixel = frameCornerHeight*frameImage.width()-1; - const int bottomBorderFirstPixel = frameImage.width()*frameImage.height()-frameCornerHeight*frameImage.width()-1; - const int rightBorderFirstPixel = frameImage.width()-frameCornerWidth; + const int topBorderLastPixel = frameCornerHeight*frameImage.width() - 1; + const int bottomBorderFirstPixel = frameImage.width() * frameImage.height() - frameCornerHeight*frameImage.width() - 1; + const int rightBorderFirstPixel = frameImage.width() - frameCornerWidth; const int leftBorderLastPixel = frameCornerWidth; while ((skips + estimations) < pixels) { - if ((skips+estimations) > topBorderLastPixel && - (skips+estimations) < bottomBorderFirstPixel) { + if ((skips + estimations) > topBorderLastPixel && + (skips + estimations) < bottomBorderFirstPixel) { for (int rowIndex = 0; rowIndex < frameImage.width(); rowIndex++) { if (rowIndex > leftBorderLastPixel && rowIndex < rightBorderFirstPixel) { @@ -529,18 +529,18 @@ void QS60StylePrivate::drawRow(QS60StyleEnums::SkinParts start, endRect = startRect.translated(rect.width() - startRect.width(), 0); middleRect.adjust(startRect.width(), 0, -startRect.width(), 0); if (startRect.bottomRight().x() > endRect.topLeft().x()) { - const int overlap = (startRect.bottomRight().x() - endRect.topLeft().x())>>1; - startRect.setWidth(startRect.width()-overlap); - endRect.adjust(overlap,0,0,0); + const int overlap = (startRect.bottomRight().x() - endRect.topLeft().x()) >> 1; + startRect.setWidth(startRect.width() - overlap); + endRect.adjust(overlap, 0, 0, 0); } } else { startRect.setHeight(qMin((rect.height() >> 1) - 1, startRect.height())); endRect = startRect.translated(0, rect.height() - startRect.height()); middleRect.adjust(0, startRect.height(), 0, -startRect.height()); if (startRect.topRight().y() > endRect.bottomLeft().y()) { - const int overlap = (startRect.topRight().y() - endRect.bottomLeft().y())>>1; - startRect.setHeight(startRect.height()-overlap); - endRect.adjust(0,overlap,0,0); + const int overlap = (startRect.topRight().y() - endRect.bottomLeft().y()) >> 1; + startRect.setHeight(startRect.height() - overlap); + endRect.adjust(0, overlap, 0, 0); } } @@ -808,9 +808,17 @@ QSize QS60StylePrivate::partSize(QS60StyleEnums::SkinParts part, SkinElementFlag case QS60StyleEnums::SP_QgnGrafTabActiveL: //Returned QSize for tabs must not be square, but narrow rectangle with width:height //ratio of 1:2 for horizontal tab bars (and 2:1 for vertical ones). - result.setWidth(result.height()>>1); + result.setWidth(result.height() >> 1); break; - case QS60StyleEnums::SP_QgnIndiSliderEdit: + + case QS60StyleEnums::SP_QgnGrafNsliderEndLeft: + case QS60StyleEnums::SP_QgnGrafNsliderEndRight: + case QS60StyleEnums::SP_QgnGrafNsliderMiddle: + result.setWidth(result.height() >> 1); + break; + + case QS60StyleEnums::SP_QgnGrafNsliderMarker: + case QS60StyleEnums::SP_QgnGrafNsliderMarkerSelected: result.scale(pixelMetric(QStyle::PM_SliderLength), pixelMetric(QStyle::PM_SliderControlThickness), Qt::IgnoreAspectRatio); break; @@ -931,22 +939,42 @@ void QS60Style::drawComplexControl(ComplexControl control, const QStyleOptionCom case CC_Slider: if (const QStyleOptionSlider *optionSlider = qstyleoption_cast<const QStyleOptionSlider *>(option)) { - // The groove is just a centered line. Maybe a qgn_graf_line_* at some point const QRect sliderGroove = subControlRect(control, optionSlider, SC_SliderGroove, widget); - const QPoint sliderGrooveCenter = sliderGroove.center(); const bool horizontal = optionSlider->orientation == Qt::Horizontal; - painter->save(); - if (widget) - painter->setPen(widget->palette().windowText().color()); - if (horizontal) - painter->drawLine(0, sliderGrooveCenter.y(), sliderGroove.right(), sliderGrooveCenter.y()); - else - painter->drawLine(sliderGrooveCenter.x(), 0, sliderGrooveCenter.x(), sliderGroove.bottom()); - painter->restore(); + //Highlight +/* if (optionSlider->state & QStyle::State_HasFocus) + drawPrimitive(PE_FrameFocusRect, optionSlider, painter, widget);*/ + + //Groove graphics + if (QS60StylePrivate::hasSliderGrooveGraphic()) { + const QS60StylePrivate::SkinElements grooveElement = horizontal ? + QS60StylePrivate::SE_SliderGrooveHorizontal : + QS60StylePrivate::SE_SliderGrooveVertical; + QS60StylePrivate::drawSkinElement(grooveElement, painter, sliderGroove, flags); + } else { + const QRect sliderGroove = subControlRect(control, optionSlider, SC_SliderGroove, widget); + const QPoint sliderGrooveCenter = sliderGroove.center(); + const bool horizontal = optionSlider->orientation == Qt::Horizontal; + painter->save(); + if (widget) + painter->setPen(widget->palette().windowText().color()); + if (horizontal) + painter->drawLine(0, sliderGrooveCenter.y(), sliderGroove.right(), sliderGrooveCenter.y()); + else + painter->drawLine(sliderGrooveCenter.x(), 0, sliderGrooveCenter.x(), sliderGroove.bottom()); + painter->restore(); + } + + //Handle graphics const QRect sliderHandle = subControlRect(control, optionSlider, SC_SliderHandle, widget); - const QS60StylePrivate::SkinElements handleElement = - horizontal ? QS60StylePrivate::SE_SliderHandleHorizontal : QS60StylePrivate::SE_SliderHandleVertical; + QS60StylePrivate::SkinElements handleElement; + if (optionSlider->state & QStyle::State_Sunken) + handleElement = + horizontal ? QS60StylePrivate::SE_SliderHandleSelectedHorizontal : QS60StylePrivate::SE_SliderHandleSelectedVertical; + else + handleElement = + horizontal ? QS60StylePrivate::SE_SliderHandleHorizontal : QS60StylePrivate::SE_SliderHandleVertical; QS60StylePrivate::drawSkinElement(handleElement, painter, sliderHandle, flags); } break; @@ -963,10 +991,11 @@ void QS60Style::drawComplexControl(ComplexControl control, const QStyleOptionCom buttonOption.QStyleOption::operator=(*cmb); const int maxHeight = cmbxFrame.height(); const int maxWidth = cmbxFrame.width() - cmbxEditField.width(); - const int topLeftPoint = direction ? cmbxEditField.right()+1 : cmbxEditField.left()+1-maxWidth; + const int topLeftPoint = direction ? + (cmbxEditField.right() + 1) : (cmbxEditField.left() + 1 - maxWidth); const QRect buttonRect(topLeftPoint, cmbxEditField.top(), maxWidth, maxHeight); buttonOption.rect = buttonRect; - buttonOption.state = cmb->state & (State_Enabled | State_MouseOver); + buttonOption.state = cmb->state; drawPrimitive(PE_PanelButtonCommand, &buttonOption, painter, widget); // draw label background - label itself is drawn separately @@ -1320,6 +1349,7 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, painter->setClipRect(voptAdj.rect); const bool isSelected = (vopt->state & QStyle::State_Selected); + const bool hasFocus = (vopt->state & QStyle::State_HasFocus); bool isScrollBarVisible = false; int scrollBarWidth = 0; @@ -1351,9 +1381,9 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, const QModelIndex index = vopt->index; //todo: Draw cell background only once - for the first cell. QStyleOptionViewItemV4 voptAdj2 = voptAdj; - const QModelIndex indexFirst = itemView->model()->index(0,0); + const QModelIndex indexFirst = itemView->model()->index(0, 0); const QModelIndex indexLast = itemView->model()->index( - itemView->model()->rowCount()-1,itemView->model()->columnCount()-1); + itemView->model()->rowCount() - 1, itemView->model()->columnCount() -1); if (itemView->viewport()) voptAdj2.rect = QRect( itemView->visualRect(indexFirst).topLeft(), itemView->visualRect(indexLast).bottomRight()).intersect(itemView->viewport()->rect()); @@ -1362,7 +1392,7 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, } else { QCommonStyle::drawPrimitive(PE_PanelItemViewItem, &voptAdj, painter, widget);} // draw the focus rect - if (isSelected) { + if (isSelected | hasFocus) { QRect highlightRect = option->rect.adjusted(1,1,-1,-1); QAbstractItemView::SelectionBehavior selectionBehavior = itemView ? itemView->selectionBehavior() : QAbstractItemView::SelectItems; @@ -1541,16 +1571,16 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, f.setPointSizeF(f.pointSizeF() * KTabFontMul); painter->setFont(f); - if (option->state & QStyle::State_Selected){ + const bool selected = optionTab.state & State_Selected; + if (selected) optionTab.palette.setColor(QPalette::Active, QPalette::WindowText, QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 3, option)); - } const bool verticalTabs = optionTab.shape == QTabBar::RoundedEast || optionTab.shape == QTabBar::RoundedWest || optionTab.shape == QTabBar::TriangularEast || optionTab.shape == QTabBar::TriangularWest; - const bool selected = optionTab.state & State_Selected; + if (verticalTabs) { painter->save(); int newX, newY, newRotation; @@ -1588,12 +1618,12 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, QPixmap tabIcon = optionTab.icon.pixmap(iconSize, (optionTab.state & State_Enabled) ? QIcon::Normal : QIcon::Disabled); if (tab->text.isEmpty()) - painter->drawPixmap(tr.center().x() - (tabIcon.height() >>1), - tr.center().y() - (tabIcon.height() >>1), + painter->drawPixmap(tr.center().x() - (tabIcon.height() >> 1), + tr.center().y() - (tabIcon.height() >> 1), tabIcon); else painter->drawPixmap(tr.left() + tabOverlap, - tr.center().y() - (tabIcon.height() >>1), + tr.center().y() - (tabIcon.height() >> 1), tabIcon); tr.setLeft(tr.left() + iconSize.width() + 4); } @@ -1622,7 +1652,7 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, if (optionProgressBar->orientation == Qt::Horizontal) { progressRect.setWidth(int(progressRect.width() * progressFactor)); if(optionProgressBar->direction == Qt::RightToLeft) - progressRect.translate(optionProgressBar->rect.width()-progressRect.width(),0); + progressRect.translate(optionProgressBar->rect.width()-progressRect.width(), 0); progressRect.adjust(1, 0, -1, 0); } else { progressRect.adjust(0, 1, 0, -1); @@ -1688,18 +1718,18 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, optionCheckBox.QStyleOptionMenuItem::operator=(*menuItem); optionCheckBox.rect.setWidth(pixelMetric(PM_IndicatorWidth)); optionCheckBox.rect.setHeight(pixelMetric(PM_IndicatorHeight)); - const int moveByX = optionCheckBox.rect.width()+vSpacing; + const int moveByX = optionCheckBox.rect.width() + vSpacing; if (optionMenuItem.direction == Qt::LeftToRight) { - textRect.translate(moveByX,0); + textRect.translate(moveByX, 0); iconRect.translate(moveByX, 0); - iconRect.setWidth(iconRect.width()+vSpacing); - textRect.setWidth(textRect.width()-moveByX-vSpacing); - optionCheckBox.rect.translate(vSpacing/2, hSpacing/2); + iconRect.setWidth(iconRect.width() + vSpacing); + textRect.setWidth(textRect.width() - moveByX - vSpacing); + optionCheckBox.rect.translate(vSpacing >> 1, hSpacing >> 1); } else { - textRect.setWidth(textRect.width()-moveByX); - iconRect.setWidth(iconRect.width()+vSpacing); - iconRect.translate(-optionCheckBox.rect.width()-vSpacing, 0); - optionCheckBox.rect.translate(textRect.width()+iconRect.width(),0); + textRect.setWidth(textRect.width() - moveByX); + iconRect.setWidth(iconRect.width() + vSpacing); + iconRect.translate(-optionCheckBox.rect.width() - vSpacing, 0); + optionCheckBox.rect.translate(textRect.width() + iconRect.width(), 0); } drawPrimitive(PE_IndicatorMenuCheckMark, &optionCheckBox, painter, widget); } @@ -1710,9 +1740,9 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, if (itemWithIcon) { drawItemPixmap(painter, iconRect, text_flags, pix); if (optionMenuItem.direction == Qt::LeftToRight) - textRect.translate(vSpacing,0); + textRect.translate(vSpacing, 0); else - textRect.translate(-vSpacing,0); + textRect.translate(-vSpacing, 0); textRect.setWidth(textRect.width()-vSpacing); } @@ -1720,7 +1750,7 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, if (drawSubMenuIndicator) { QStyleOptionMenuItem arrowOptions; arrowOptions.QStyleOption::operator=(*menuItem); - const int indicatorWidth = (pixelMetric(PM_ListViewIconSize, option, widget)>>1) + + const int indicatorWidth = (pixelMetric(PM_ListViewIconSize, option, widget) >> 1) + pixelMetric(QStyle::PM_LayoutVerticalSpacing, option, widget); if (optionMenuItem.direction == Qt::LeftToRight) arrowOptions.rect.setLeft(textRect.right()); @@ -1765,8 +1795,8 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, painter->save(); QPen linePen = QPen(QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 1, header)); const int penWidth = (header->orientation == Qt::Horizontal) ? - linePen.width()+QS60StylePrivate::pixelMetric(PM_Custom_BoldLineWidth) - : linePen.width()+QS60StylePrivate::pixelMetric(PM_Custom_ThinLineWidth); + linePen.width() + QS60StylePrivate::pixelMetric(PM_Custom_BoldLineWidth) + : linePen.width() + QS60StylePrivate::pixelMetric(PM_Custom_ThinLineWidth); linePen.setWidth(penWidth); painter->setPen(linePen); if (header->orientation == Qt::Horizontal){ @@ -1785,7 +1815,7 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, //Make cornerButton slightly smaller so that it is not on top of table border graphic. QStyleOptionHeader subopt = *header; const int borderTweak = - QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth)>>1; + QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth) >> 1; if (subopt.direction == Qt::LeftToRight) subopt.rect.adjust(borderTweak, borderTweak, 0, -borderTweak); else @@ -1878,9 +1908,9 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, } else { const int frameWidth = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); if (option->direction == Qt::LeftToRight) - headerRect.adjust(-2*frameWidth, 0, 0, 0); + headerRect.adjust(-2 * frameWidth, 0, 0, 0); else - headerRect.adjust(0, 0, 2*frameWidth, 0); + headerRect.adjust(0, 0, 2 * frameWidth, 0); } if (option->palette.brush(QPalette::Button).color() == Qt::transparent) QS60StylePrivate::drawSkinElement( @@ -2003,7 +2033,7 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti QRect tickRect = option->rect; const int frameBorderWidth = QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth); // adjust tickmark rect to exclude frame border - tickRect.adjust(0,-frameBorderWidth,0,-frameBorderWidth); + tickRect.adjust(0, -frameBorderWidth, 0, -frameBorderWidth); QS60StyleEnums::SkinParts skinPart = QS60StyleEnums::SP_QgnIndiMarkedAdd; QS60StylePrivate::drawSkinPart(skinPart, painter, tickRect, (flags | QS60StylePrivate::SF_ColorSkinned)); @@ -2015,7 +2045,7 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti case PE_IndicatorRadioButton: { QRect buttonRect = option->rect; //there is empty (a. 33%) space in svg graphics for radiobutton - const qreal reduceWidth = (qreal)buttonRect.width()/3.0; + const qreal reduceWidth = (qreal)buttonRect.width() / 3.0; const qreal rectWidth = (qreal)option->rect.width() != 0 ? option->rect.width() : 1.0; // Try to occupy the full area const qreal scaler = 1 + (reduceWidth/rectWidth); @@ -2078,27 +2108,28 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti case PE_IndicatorSpinDown: case PE_IndicatorSpinUp: if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { - QStyleOptionSpinBox optionSpinBox = *spinBox; - if (QS60StylePrivate::canDrawThemeBackground(optionSpinBox.palette.base())) { + if (QS60StylePrivate::canDrawThemeBackground(spinBox->palette.base())) { + QStyleOptionSpinBox optionSpinBox = *spinBox; const QS60StyleEnums::SkinParts part = (element == PE_IndicatorSpinUp) ? QS60StyleEnums::SP_QgnGrafScrollArrowUp : QS60StyleEnums::SP_QgnGrafScrollArrowDown; - const int adjustment = qMin(optionSpinBox.rect.width(), optionSpinBox.rect.height())/6; - optionSpinBox.rect.translate(0, (element == PE_IndicatorSpinDown) ? adjustment : -adjustment ); - QS60StylePrivate::drawSkinPart(part, painter, optionSpinBox.rect,flags); + const int iconMargin = QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth) >> 1; + optionSpinBox.rect.translate(0, (element == PE_IndicatorSpinDown) ? iconMargin : -iconMargin ); + QS60StylePrivate::drawSkinPart(part, painter, optionSpinBox.rect, flags); } else { commonStyleDraws = true; } } +#endif //QT_NO_SPINBOX #ifndef QT_NO_COMBOBOX - else if (const QStyleOptionFrame *cmb = qstyleoption_cast<const QStyleOptionFrame *>(option)) { + if (const QStyleOptionFrame *cmb = qstyleoption_cast<const QStyleOptionFrame *>(option)) { if (QS60StylePrivate::canDrawThemeBackground( option->palette.base())) { // We want to draw down arrow here for comboboxes as well. + QStyleOptionFrame optionsComboBox = *cmb; const QS60StyleEnums::SkinParts part = QS60StyleEnums::SP_QgnGrafScrollArrowDown; - QStyleOptionFrame comboBox = *cmb; - const int adjustment = qMin(comboBox.rect.width(), comboBox.rect.height())/6; - comboBox.rect.translate(0, (element == PE_IndicatorSpinDown) ? adjustment : -adjustment ); - QS60StylePrivate::drawSkinPart(part, painter, comboBox.rect,flags); + const int iconMargin = QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth) >> 1; + optionsComboBox.rect.translate(0, (element == PE_IndicatorSpinDown) ? iconMargin : -iconMargin ); + QS60StylePrivate::drawSkinPart(part, painter, optionsComboBox.rect, flags); } else { commonStyleDraws = true; } @@ -2116,12 +2147,11 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti // We want to draw down arrow here for comboboxes as well. QStyleOptionFrame comboBox = *cmb; const int frameWidth = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); - comboBox.rect.adjust(0,frameWidth,0,-frameWidth); + comboBox.rect.adjust(0, frameWidth, 0, -frameWidth); QCommonStyle::drawPrimitive(element, &comboBox, painter, widget); } #endif //QT_NO_COMBOBOX break; -#endif //QT_NO_SPINBOX case PE_Widget: if (QS60StylePrivate::drawsOwnThemeBackground(widget) #ifndef QT_NO_COMBOBOX @@ -2131,7 +2161,10 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti || qobject_cast<const QMenu *> (widget) #endif //QT_NO_MENU ) { - if (QS60StylePrivate::canDrawThemeBackground(option->palette.base())) + //Need extra check since dialogs have their own theme background + if (QS60StylePrivate::canDrawThemeBackground(option->palette.base()) && + option->palette.window().texture().cacheKey() == + QS60StylePrivate::m_themePalette->window().texture().cacheKey()) QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_OptionsMenu, painter, option->rect, flags); else commonStyleDraws = true; @@ -2241,11 +2274,13 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti } break; + case PE_PanelScrollAreaCorner: + break; + // todo: items are below with #ifdefs "just in case". in final version, remove all non-required cases case PE_FrameLineEdit: case PE_IndicatorDockWidgetResizeHandle: case PE_PanelTipLabel: - case PE_PanelScrollAreaCorner: #ifndef QT_NO_TABBAR case PE_IndicatorTabTear: // No tab tear in S60 @@ -2287,6 +2322,13 @@ int QS60Style::pixelMetric(PixelMetric metric, const QStyleOption *option, const metricValue = -menuWidth; } } + //if layout direction is mirrored, switch left and right border margins + if (option && option->direction == Qt::RightToLeft) { + if (metric == PM_LayoutLeftMargin) + metricValue = QS60StylePrivate::pixelMetric(PM_LayoutRightMargin); + else if (metric == PM_LayoutRightMargin) + metricValue = QS60StylePrivate::pixelMetric(PM_LayoutLeftMargin); + } return metricValue; } @@ -2299,22 +2341,22 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, case CT_ToolButton: sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); //FIXME properly - style should calculate the location of border frame-part - sz += QSize(2*pixelMetric(PM_ButtonMargin), 2*pixelMetric(PM_ButtonMargin)); + sz += QSize(2 * pixelMetric(PM_ButtonMargin), 2 * pixelMetric(PM_ButtonMargin)); if (const QStyleOptionToolButton *toolBtn = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) if (toolBtn->subControls & SC_ToolButtonMenu) - sz += QSize(pixelMetric(PM_MenuButtonIndicator),0); + sz += QSize(pixelMetric(PM_MenuButtonIndicator), 0); break; case CT_PushButton: sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); //FIXME properly - style should calculate the location of border frame-part - sz += QSize(2*pixelMetric(PM_ButtonMargin), 2*pixelMetric(PM_ButtonMargin)); + sz += QSize(2 * pixelMetric(PM_ButtonMargin), 2 * pixelMetric(PM_ButtonMargin)); if (const QAbstractButton *buttonWidget = (qobject_cast<const QAbstractButton *>(widget))) if (buttonWidget->isCheckable()) sz += QSize(pixelMetric(PM_IndicatorWidth) + pixelMetric(PM_CheckBoxLabelSpacing), 0); break; case CT_LineEdit: if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) - sz += QSize(2*f->lineWidth, 4*f->lineWidth); + sz += QSize(2 * f->lineWidth, 4 * f->lineWidth); break; case CT_TabBarTab: { @@ -2329,7 +2371,7 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, if (QS60StylePrivate::isTouchSupported()) //Make itemview easier to use in touch devices //QCommonStyle does not adjust height with horizontal margin, it only adjusts width - sz.setHeight(sz.height() + 2*pixelMetric(QStyle::PM_FocusFrameVMargin)); + sz.setHeight(sz.height() + 2 * pixelMetric(QStyle::PM_FocusFrameVMargin)); break; default: sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); @@ -2345,10 +2387,10 @@ int QS60Style::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w int retValue = -1; switch (sh) { case SH_Table_GridLineColor: - retValue = int(QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors,2,0).rgba()); + retValue = int(QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 2, 0).rgba()); break; case SH_GroupBox_TextLabelColor: - retValue = int(QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors,6,0).rgba()); + retValue = int(QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0).rgba()); break; case SH_ScrollBar_ScrollWhenPointerLeavesControl: retValue = true; @@ -2430,7 +2472,7 @@ QRect QS60Style::subControlRect(ComplexControl control, const QStyleOptionComple sliderlen = (qint64(scrollbarOption->pageStep) * maxlen) / (range + scrollbarOption->pageStep); const int slidermin = pixelMetric(PM_ScrollBarSliderMin, scrollbarOption, widget); - if (sliderlen < slidermin || range > (INT_MAX>>1)) + if (sliderlen < slidermin || range > (INT_MAX >> 1)) sliderlen = slidermin; if (sliderlen > maxlen) sliderlen = maxlen; @@ -2481,39 +2523,40 @@ QRect QS60Style::subControlRect(ComplexControl control, const QStyleOptionComple if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { const int frameThickness = spinbox->frame ? pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget) : 0; const int buttonMargin = spinbox->frame ? 2 : 0; - const int buttonWidth = QS60StylePrivate::pixelMetric(QStyle::PM_ButtonIconSize) + 2*buttonMargin; + const int buttonWidth = QS60StylePrivate::pixelMetric(QStyle::PM_ButtonIconSize) + 2 * buttonMargin; QSize buttonSize; buttonSize.setHeight(qMax(8, spinbox->rect.height() - frameThickness)); - buttonSize.setWidth(buttonWidth); + //width should at least be equal to height + buttonSize.setWidth(qMax(buttonSize.height(), buttonWidth)); buttonSize = buttonSize.expandedTo(QApplication::globalStrut()); const int y = frameThickness + spinbox->rect.y(); - const int x = spinbox->rect.x() + spinbox->rect.width() - frameThickness - 2*buttonSize.width(); + const int x = spinbox->rect.x() + spinbox->rect.width() - frameThickness - 2 * buttonSize.width(); switch (scontrol) { case SC_SpinBoxUp: if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) return QRect(); - ret = QRect(x, y, buttonWidth, buttonSize.height()); + ret = QRect(x, y, buttonSize.width(), buttonSize.height()); break; case SC_SpinBoxDown: if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) return QRect(); - ret = QRect(x+buttonSize.width(), y, buttonWidth, buttonSize.height()); + ret = QRect(x + buttonSize.width(), y, buttonSize.width(), buttonSize.height()); break; case SC_SpinBoxEditField: if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) ret = QRect( frameThickness, frameThickness, - spinbox->rect.width() - 2*frameThickness, - spinbox->rect.height() - 2*frameThickness); + spinbox->rect.width() - 2 * frameThickness, + spinbox->rect.height() - 2 * frameThickness); else ret = QRect( frameThickness, frameThickness, x - frameThickness, - spinbox->rect.height() - 2*frameThickness); + spinbox->rect.height() - 2 * frameThickness); break; case SC_SpinBoxFrame: ret = spinbox->rect; @@ -2529,29 +2572,29 @@ QRect QS60Style::subControlRect(ComplexControl control, const QStyleOptionComple ret = cmb->rect; const int width = cmb->rect.width(); const int height = cmb->rect.height(); + const int buttonIconSize = QS60StylePrivate::pixelMetric(QStyle::PM_ButtonIconSize); const int buttonMargin = cmb->frame ? 2 : 0; // lets use spinbox frame here as well, as no combobox specific value available. const int frameThickness = cmb->frame ? pixelMetric(PM_SpinBoxFrameWidth, cmb, widget) : 0; - const int buttonWidth = QS60StylePrivate::pixelMetric(QStyle::PM_ButtonIconSize); + const int buttonWidth = qMax(cmb->rect.height(), buttonIconSize); + const int xposMod = (cmb->rect.x()) + width - buttonMargin - buttonWidth; + const int ypos = cmb->rect.y(); QSize buttonSize; - buttonSize.setHeight(qMax(8, (cmb->rect.height()>>1) - frameThickness)); //minimum of 8 pixels - buttonSize.setWidth(buttonWidth+2*buttonMargin); + buttonSize.setWidth(buttonWidth + 2 * buttonMargin); + buttonSize.setHeight(qMax(8, (cmb->rect.height() >> 1) - frameThickness)); //buttons should be squares buttonSize = buttonSize.expandedTo(QApplication::globalStrut()); switch (scontrol) { case SC_ComboBoxArrow: - ret.setRect( - ret.x() + ret.width() - buttonMargin - buttonWidth, - ret.y() + buttonMargin, - buttonWidth, - height - 2*buttonMargin); + ret.setRect(xposMod, ypos + buttonMargin, buttonWidth, height - 2 * buttonMargin); break; case SC_ComboBoxEditField: { - ret.setRect( - ret.x() + frameThickness, - ret.y() + frameThickness, - ret.width() - 2*frameThickness - buttonSize.width(), - ret.height() - 2*frameThickness); + const int withFrameX = cmb->rect.x() + cmb->rect.width() - frameThickness - buttonSize.width(); + ret = QRect( + frameThickness, + frameThickness, + withFrameX - frameThickness, + cmb->rect.height() - 2 * frameThickness); } break; default: @@ -2568,7 +2611,7 @@ QRect QS60Style::subControlRect(ComplexControl control, const QStyleOptionComple //slightly indent text and boxes, so that dialog border does not mess with them. const int horizontalSpacing = QS60StylePrivate::pixelMetric(QStyle::PM_LayoutHorizontalSpacing); - ret.adjust(2,horizontalSpacing-3,0,0); + ret.adjust(2, horizontalSpacing - 3, 0, 0); } break; case SC_GroupBoxFrame: { @@ -2576,7 +2619,7 @@ QRect QS60Style::subControlRect(ComplexControl control, const QStyleOptionComple const int tbHeight = textBox.height(); ret.translate(0, -ret.y()); // include title to within the groupBox frame - ret.setHeight(ret.height()+tbHeight); + ret.setHeight(ret.height() + tbHeight); if (widget && ret.bottom() > widget->rect().bottom()) ret.setBottom(widget->rect().bottom()); } @@ -2588,7 +2631,7 @@ QRect QS60Style::subControlRect(ComplexControl control, const QStyleOptionComple break; case CC_ToolButton: if (const QStyleOptionToolButton *toolButton = qstyleoption_cast<const QStyleOptionToolButton *>(option)) { - const int indicatorRect = pixelMetric(PM_MenuButtonIndicator) + 2*pixelMetric(PM_ButtonMargin); + const int indicatorRect = pixelMetric(PM_MenuButtonIndicator) + 2 * pixelMetric(PM_ButtonMargin); const int border = pixelMetric(PM_ButtonMargin) + pixelMetric(PM_DefaultFrameWidth); ret = toolButton->rect; const bool popup = (toolButton->features & @@ -2626,13 +2669,13 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con // in S60 the input text box doesn't start from line Edit's TL, but // a bit indented. QRect lineEditRect = opt->rect; - const int adjustment = opt->rect.height()>>2; - lineEditRect.adjust(adjustment,0,0,0); + const int adjustment = opt->rect.height() >> 2; + lineEditRect.adjust(adjustment, 0, 0, 0); ret = lineEditRect; } break; case SE_TabBarTearIndicator: - ret = QRect(0,0,0,0); + ret = QRect(0, 0, 0, 0); break; case SE_TabWidgetTabBar: if (const QStyleOptionTabWidgetFrame *optionTab = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) { @@ -2654,12 +2697,12 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con // make sure that gain does not set the rect outside of widget boundaries if (twf->direction == Qt::RightToLeft) { if ((ret.left() - gain) < widget->rect().left()) - gain = widget->rect().left()-ret.left(); - ret.adjust(-gain,0,0,0); + gain = widget->rect().left() - ret.left(); + ret.adjust(-gain, 0, 0, 0); } else { if ((ret.right() + gain) > widget->rect().right()) - gain = widget->rect().right()-ret.right(); - ret.adjust(0,0,gain,0); + gain = widget->rect().right() - ret.right(); + ret.adjust(0, 0, gain, 0); } } break; @@ -2667,8 +2710,8 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con default: { if (widget) { if ((ret.bottom() + gain) > widget->rect().bottom()) - gain = widget->rect().bottom()-ret.bottom(); - ret.adjust(0,0,0,gain); + gain = widget->rect().bottom() - ret.bottom(); + ret.adjust(0, 0, 0, gain); } break; } @@ -2694,7 +2737,7 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con QS60StylePrivate::pixelMetric(QStyle::PM_LayoutVerticalSpacing); //const int horizontalSpacing = QS60StylePrivate::pixelMetric(QStyle::PM_LayoutHorizontalSpacing); const int checkBoxRectWidth = subElementRect(SE_ItemViewItemCheckIndicator, opt, widget).width(); - ret.adjust(-checkBoxRectWidth-verticalSpacing,0,-checkBoxRectWidth-verticalSpacing,0); + ret.adjust(-checkBoxRectWidth - verticalSpacing, 0, -checkBoxRectWidth - verticalSpacing, 0); } } else if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) { const bool checkable = menuItem->checkType != QStyleOptionMenuItem::NotCheckable; @@ -2719,9 +2762,9 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu){ // submenu indicator is very small, so lets halve the rect if (menuItem->direction == Qt::LeftToRight) - ret.adjust(0,0,-(indicatorWidth >> 1),0); + ret.adjust(0, 0, -(indicatorWidth >> 1), 0); else - ret.adjust((indicatorWidth >> 1),0,0,0); + ret.adjust((indicatorWidth >> 1), 0, 0, 0); } } } @@ -2745,14 +2788,14 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con const int itemHeight = opt->rect.height(); int heightOffset = 0; if (indicatorHeight < itemHeight) - heightOffset = ((itemHeight - indicatorHeight)>>1); + heightOffset = ((itemHeight - indicatorHeight) >> 1); if (checkBoxOnly) { // Move rect and make it slightly smaller, so that // a) highlight border does not cross the rect // b) in s60 list checkbox is smaller than normal checkbox //todo; magic three - ret.setRect(opt->rect.left()+3, opt->rect.top() + heightOffset, - indicatorWidth-3, indicatorHeight-3); + ret.setRect(opt->rect.left() + 3, opt->rect.top() + heightOffset, + indicatorWidth - 3, indicatorHeight - 3); } else { ret.setRect(opt->rect.right() - indicatorWidth - spacing, opt->rect.top() + heightOffset, indicatorWidth, indicatorHeight); @@ -2916,7 +2959,7 @@ QIcon QS60Style::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const { const int iconDimension = QS60StylePrivate::pixelMetric(QStyle::PM_ToolBarIconSize); - const QRect iconSize = (!option) ? QRect(0,0,iconDimension,iconDimension) : option->rect; + const QRect iconSize = (!option) ? QRect(0, 0, iconDimension, iconDimension) : option->rect; QS60StyleEnums::SkinParts part; QS60StylePrivate::SkinElementFlags adjustedFlags; if (option) diff --git a/src/gui/styles/qs60style_p.h b/src/gui/styles/qs60style_p.h index 5ab2308..65d7574 100644 --- a/src/gui/styles/qs60style_p.h +++ b/src/gui/styles/qs60style_p.h @@ -119,6 +119,9 @@ public: SP_QgnGrafTabPassiveL, SP_QgnGrafTabPassiveM, SP_QgnGrafTabPassiveR, + SP_QgnGrafNsliderEndLeft, + SP_QgnGrafNsliderEndRight, + SP_QgnGrafNsliderMiddle, SP_QgnIndiCheckboxOff, SP_QgnIndiCheckboxOn, SP_QgnIndiHlColSuper, // Available in S60 release 3.2 and later. @@ -131,7 +134,8 @@ public: SP_QgnIndiNaviArrowRight, SP_QgnIndiRadiobuttOff, SP_QgnIndiRadiobuttOn, - SP_QgnIndiSliderEdit, + SP_QgnGrafNsliderMarker, + SP_QgnGrafNsliderMarkerSelected, SP_QgnIndiSubMenu, SP_QgnNoteErased, SP_QgnNoteError, @@ -313,6 +317,10 @@ public: SE_ScrollBarHandleVertical, SE_SliderHandleHorizontal, SE_SliderHandleVertical, + SE_SliderHandleSelectedHorizontal, + SE_SliderHandleSelectedVertical, + SE_SliderGrooveVertical, + SE_SliderGrooveHorizontal, SE_TabBarTabEastActive, SE_TabBarTabEastInactive, SE_TabBarTabNorthActive, @@ -403,6 +411,7 @@ public: static bool isTouchSupported(); static bool isToolBarBackground(); + static bool hasSliderGrooveGraphic(); // calculates average color based on button skin graphics (minus borders). QColor colorFromFrameGraphics(SkinFrameElements frame) const; @@ -443,7 +452,7 @@ public: static QSize naviPaneSize(); //Checks that the current brush is transparent or has BrushStyle NoBrush, - //so that theme graphic background can be drawn. + //so that theme graphic background can be drawn. static bool canDrawThemeBackground(const QBrush &backgroundBrush); private: diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp index 48b8fad..fb9665a 100644 --- a/src/gui/styles/qs60style_s60.cpp +++ b/src/gui/styles/qs60style_s60.cpp @@ -62,6 +62,7 @@ #include <AknLayoutFont.h> #include <aknutils.h> #include <aknnavi.h> +#include <gulicon.h> #if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN) @@ -69,6 +70,7 @@ QT_BEGIN_NAMESPACE enum TDrawType { EDrawIcon, + EDrawGulIcon, EDrawBackground, ENoDraw }; @@ -80,8 +82,11 @@ enum TSupportRelease { ES60_5_0 = 0x0004, ES60_5_1 = 0x0008, ES60_5_2 = 0x0010, + ES60_3_X = ES60_3_1 | ES60_3_2, + // Releases before Symbian Foundation + ES60_PreSF = ES60_3_1 | ES60_3_2 | ES60_5_0, // Add all new releases here - ES60_AllReleases = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 + ES60_All = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 }; typedef struct { @@ -101,11 +106,12 @@ public: static QPixmap colorSkinnedGraphics(const QS60StyleEnums::SkinParts &stylepart, const QSize &size, QPainter *painter, QS60StylePrivate::SkinElementFlags flags); static QColor colorValue(const TAknsItemID &colorGroup, int colorIndex); - static QPixmap fromFbsBitmap(CFbsBitmap *icon, CFbsBitmap *mask, QS60StylePrivate::SkinElementFlags flags, QImage::Format format); + static QPixmap fromFbsBitmap(CFbsBitmap *icon, CFbsBitmap *mask, QS60StylePrivate::SkinElementFlags flags, const TSize& targetSize); static bool disabledPartGraphic(QS60StyleEnums::SkinParts &part); static bool disabledFrameGraphic(QS60StylePrivate::SkinFrameElements &frame); static QPixmap generateMissingThemeGraphic(QS60StyleEnums::SkinParts &part, const QSize &size, QS60StylePrivate::SkinElementFlags flags); static QSize naviPaneSize(); + static TAknsItemID partSpecificThemeId(int part); private: static QPixmap createSkinnedGraphicsLX(QS60StyleEnums::SkinParts part, @@ -115,209 +121,214 @@ private: const QSize &size, QPainter *painter, QS60StylePrivate::SkinElementFlags flags); static void frameIdAndCenterId(QS60StylePrivate::SkinFrameElements frameElement, TAknsItemID &frameId, TAknsItemID ¢erId); static TRect innerRectFromElement(QS60StylePrivate::SkinFrameElements frameElement, const TRect &outerRect); - static void checkAndUnCompressBitmapL(CFbsBitmap*& aOriginalBitmap); - static void checkAndUnCompressBitmap(CFbsBitmap*& aOriginalBitmap); - static void unCompressBitmapL(const TRect& aTrgRect, CFbsBitmap* aTrgBitmap, CFbsBitmap* aSrcBitmap); - static void fallbackInfo(const QS60StyleEnums::SkinParts &stylepart, TDes& fallbackFileName, TInt& fallbackIndex); + static void fallbackInfo(const QS60StyleEnums::SkinParts &stylePart, TInt &fallbackIndex); static bool checkSupport(const int supportedRelease); - static TAknsItemID checkAndUpdateReleaseSpecificGraphics(int part); // Array to match the skin ID, fallback graphics and Qt widget graphics. static const partMapEntry m_partMap[]; }; const partMapEntry QS60StyleModeSpecifics::m_partMap[] = { - /* SP_QgnGrafBarWait */ {KAknsIIDQgnGrafBarWaitAnim, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafBarFrameCenter */ {KAknsIIDQgnGrafBarFrameCenter, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafBarFrameSideL */ {KAknsIIDQgnGrafBarFrameSideL, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafBarFrameSideR */ {KAknsIIDQgnGrafBarFrameSideR, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafBarProgress */ {KAknsIIDQgnGrafBarProgress, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafScrollArrowDown */ {KAknsIIDQgnGrafScrollArrowDown, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafScrollArrowLeft */ {KAknsIIDQgnGrafScrollArrowLeft, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafScrollArrowRight */ {KAknsIIDQgnGrafScrollArrowRight, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafScrollArrowUp */ {KAknsIIDQgnGrafScrollArrowUp, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafTabActiveL */ {KAknsIIDQgnGrafTabActiveL, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafTabActiveM */ {KAknsIIDQgnGrafTabActiveM, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafTabActiveR */ {KAknsIIDQgnGrafTabActiveR, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafTabPassiveL */ {KAknsIIDQgnGrafTabPassiveL, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafTabPassiveM */ {KAknsIIDQgnGrafTabPassiveM, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnGrafTabPassiveR */ {KAknsIIDQgnGrafTabPassiveR, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnIndiCheckboxOff */ {KAknsIIDQgnIndiCheckboxOff, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnIndiCheckboxOn */ {KAknsIIDQgnIndiCheckboxOn, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafBarWait */ {KAknsIIDQgnGrafBarWaitAnim, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnGrafBarFrameCenter */ {KAknsIIDQgnGrafBarFrameCenter, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnGrafBarFrameSideL */ {KAknsIIDQgnGrafBarFrameSideL, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnGrafBarFrameSideR */ {KAknsIIDQgnGrafBarFrameSideR, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnGrafBarProgress */ {KAknsIIDQgnGrafBarProgress, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnGrafScrollArrowDown */ {KAknsIIDQgnGrafScrollArrowDown, EDrawGulIcon, ES60_All, -1,-1}, + /* SP_QgnGrafScrollArrowLeft */ {KAknsIIDQgnGrafScrollArrowLeft, EDrawGulIcon, ES60_All, -1,-1}, + /* SP_QgnGrafScrollArrowRight */ {KAknsIIDQgnGrafScrollArrowRight, EDrawGulIcon, ES60_All, -1,-1}, + /* SP_QgnGrafScrollArrowUp */ {KAknsIIDQgnGrafScrollArrowUp, EDrawGulIcon, ES60_All, -1,-1}, + /* SP_QgnGrafTabActiveL */ {KAknsIIDQgnGrafTabActiveL, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnGrafTabActiveM */ {KAknsIIDQgnGrafTabActiveM, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnGrafTabActiveR */ {KAknsIIDQgnGrafTabActiveR, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnGrafTabPassiveL */ {KAknsIIDQgnGrafTabPassiveL, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnGrafTabPassiveM */ {KAknsIIDQgnGrafTabPassiveM, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnGrafTabPassiveR */ {KAknsIIDQgnGrafTabPassiveR, EDrawIcon, ES60_All, -1,-1}, + + // In 3.1 there is no slider groove. + /* SP_QgnGrafNsliderEndLeft */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x19cf /* KAknsIIDQgnGrafNsliderEndLeft */}, + /* SP_QgnGrafNsliderEndRight */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x19d0 /* KAknsIIDQgnGrafNsliderEndRight */}, + /* SP_QgnGrafNsliderMiddle */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x19d2 /* KAknsIIDQgnGrafNsliderMiddle */}, + /* SP_QgnIndiCheckboxOff */ {KAknsIIDQgnIndiCheckboxOff, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnIndiCheckboxOn */ {KAknsIIDQgnIndiCheckboxOn, EDrawIcon, ES60_All, -1,-1}, + // Following 5 items (SP_QgnIndiHlColSuper - SP_QgnIndiHlLineStraight) are available starting from S60 release 3.2. // In 3.1 CommonStyle drawing is used for these QTreeView elements, since no similar icons in AVKON UI. - /* SP_QgnIndiHlColSuper */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d5 /* KAknsIIDQgnIndiHlColSuper */}, - /* SP_QgnIndiHlExpSuper */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d6 /* KAknsIIDQgnIndiHlExpSuper */}, - /* SP_QgnIndiHlLineBranch */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d7 /* KAknsIIDQgnIndiHlLineBranch */}, - /* SP_QgnIndiHlLineEnd */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d8 /* KAknsIIDQgnIndiHlLineEnd */}, - /* SP_QgnIndiHlLineStraight */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d9 /* KAknsIIDQgnIndiHlLineStraight */}, - /* SP_QgnIndiMarkedAdd */ {KAknsIIDQgnIndiMarkedAdd, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnIndiNaviArrowLeft */ {KAknsIIDQgnGrafScrollArrowLeft, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnIndiNaviArrowRight */ {KAknsIIDQgnGrafScrollArrowRight, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnIndiRadiobuttOff */ {KAknsIIDQgnIndiRadiobuttOff, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnIndiRadiobuttOn */ {KAknsIIDQgnIndiRadiobuttOn, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnIndiSliderEdit */ {KAknsIIDQgnIndiSliderEdit, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnIndiSubMenu */ {KAknsIIDQgnIndiSubmenu, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnNoteErased */ {KAknsIIDQgnNoteErased, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnNoteError */ {KAknsIIDQgnNoteError, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnNoteInfo */ {KAknsIIDQgnNoteInfo, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnNoteOk */ {KAknsIIDQgnNoteOk, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnNoteQuery */ {KAknsIIDQgnNoteQuery, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnNoteWarning */ {KAknsIIDQgnNoteWarning, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnPropFileSmall */ {KAknsIIDQgnPropFileSmall, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnPropFolderCurrent */ {KAknsIIDQgnPropFolderCurrent, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnPropFolderSmall */ {KAknsIIDQgnPropFolderSmall, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnPropFolderSmallNew */ {KAknsIIDQgnPropFolderSmallNew, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QgnPropPhoneMemcLarge */ {KAknsIIDQgnPropPhoneMemcLarge, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiHlColSuper */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d5 /* KAknsIIDQgnIndiHlColSuper */}, + /* SP_QgnIndiHlExpSuper */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d6 /* KAknsIIDQgnIndiHlExpSuper */}, + /* SP_QgnIndiHlLineBranch */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d7 /* KAknsIIDQgnIndiHlLineBranch */}, + /* SP_QgnIndiHlLineEnd */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d8 /* KAknsIIDQgnIndiHlLineEnd */}, + /* SP_QgnIndiHlLineStraight */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d9 /* KAknsIIDQgnIndiHlLineStraight */}, + /* SP_QgnIndiMarkedAdd */ {KAknsIIDQgnIndiMarkedAdd, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnIndiNaviArrowLeft */ {KAknsIIDQgnIndiNaviArrowLeft, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnIndiNaviArrowRight */ {KAknsIIDQgnIndiNaviArrowRight, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnIndiRadiobuttOff */ {KAknsIIDQgnIndiRadiobuttOff, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnIndiRadiobuttOn */ {KAknsIIDQgnIndiRadiobuttOn, EDrawIcon, ES60_All, -1,-1}, + + // In 3.1 there different slider graphic and no pressed state. + /* SP_QgnGrafNsliderMarker */ {KAknsIIDQgnIndiSliderEdit, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x19d1 /* KAknsIIDQgnGrafNsliderMarker */}, + /* SP_QgnGrafNsliderMarkerSelected */ {KAknsIIDQgnIndiSliderEdit, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x1a4a /* KAknsIIDQgnGrafNsliderMarkerSelected */}, + /* SP_QgnIndiSubMenu */ {KAknsIIDQgnIndiSubmenu, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnNoteErased */ {KAknsIIDQgnNoteErased, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnNoteError */ {KAknsIIDQgnNoteError, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnNoteInfo */ {KAknsIIDQgnNoteInfo, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnNoteOk */ {KAknsIIDQgnNoteOk, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnNoteQuery */ {KAknsIIDQgnNoteQuery, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnNoteWarning */ {KAknsIIDQgnNoteWarning, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnPropFileSmall */ {KAknsIIDQgnPropFileSmall, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnPropFolderCurrent */ {KAknsIIDQgnPropFolderCurrent, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnPropFolderSmall */ {KAknsIIDQgnPropFolderSmall, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnPropFolderSmallNew */ {KAknsIIDQgnPropFolderSmallNew, EDrawIcon, ES60_All, -1,-1}, + /* SP_QgnPropPhoneMemcLarge */ {KAknsIIDQgnPropPhoneMemcLarge, EDrawIcon, ES60_All, -1,-1}, // 3.1 & 3.2 do not have pressed state for scrollbar, so use normal scrollbar graphics instead. - /* SP_QsnCpScrollHandleBottomPressed*/ {KAknsIIDQsnCpScrollHandleBottom, EDrawIcon, ES60_3_1 | ES60_3_2, EAknsMajorGeneric, 0x20f8}, /*KAknsIIDQsnCpScrollHandleBottomPressed*/ - /* SP_QsnCpScrollHandleMiddlePressed*/ {KAknsIIDQsnCpScrollHandleMiddle, EDrawIcon, ES60_3_1 | ES60_3_2, EAknsMajorGeneric, 0x20f9}, /*KAknsIIDQsnCpScrollHandleMiddlePressed*/ - /* SP_QsnCpScrollHandleTopPressed*/ {KAknsIIDQsnCpScrollHandleTop, EDrawIcon, ES60_3_1 | ES60_3_2, EAknsMajorGeneric, 0x20fa}, /*KAknsIIDQsnCpScrollHandleTopPressed*/ - - /* SP_QsnBgScreen */ {KAknsIIDQsnBgScreen, EDrawBackground, ES60_AllReleases, -1,-1}, - - /* SP_QsnCpScrollBgBottom */ {KAknsIIDQsnCpScrollBgBottom, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QsnCpScrollBgMiddle */ {KAknsIIDQsnCpScrollBgMiddle, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QsnCpScrollBgTop */ {KAknsIIDQsnCpScrollBgTop, EDrawIcon, ES60_AllReleases, -1,-1}, - - /* SP_QsnCpScrollHandleBottom */ {KAknsIIDQsnCpScrollHandleBottom, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QsnCpScrollHandleMiddle */ {KAknsIIDQsnCpScrollHandleMiddle, EDrawIcon, ES60_AllReleases, -1,-1}, - /* SP_QsnCpScrollHandleTop */ {KAknsIIDQsnCpScrollHandleTop, EDrawIcon, ES60_AllReleases, -1,-1}, - - /* SP_QsnFrButtonTbCornerTl */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, //todo: use "normal button" from 5.0 onwards - /* SP_QsnFrButtonTbCornerTr */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbCornerBl */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbCornerBr */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbSideT */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbSideB */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbSideL */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbSideR */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbCenter */ {KAknsIIDQsnFrButtonTbCenter, EDrawIcon, ES60_AllReleases, -1,-1}, - - /* SP_QsnFrButtonTbCornerTlPressed */{KAknsIIDQsnFrButtonTbCornerTlPressed, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbCornerTrPressed */{KAknsIIDQsnFrButtonTbCornerTrPressed, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbCornerBlPressed */{KAknsIIDQsnFrButtonTbCornerBlPressed, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbCornerBrPressed */{KAknsIIDQsnFrButtonTbCornerBrPressed, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbSideTPressed */ {KAknsIIDQsnFrButtonTbSideTPressed, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbSideBPressed */ {KAknsIIDQsnFrButtonTbSideBPressed, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbSideLPressed */ {KAknsIIDQsnFrButtonTbSideLPressed, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbSideRPressed */ {KAknsIIDQsnFrButtonTbSideRPressed, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrButtonTbCenterPressed */ {KAknsIIDQsnFrButtonTbCenterPressed, EDrawIcon, ES60_AllReleases, -1,-1}, - - /* SP_QsnFrCaleCornerTl */ {KAknsIIDQsnFrCaleCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleCornerTr */ {KAknsIIDQsnFrCaleCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleCornerBl */ {KAknsIIDQsnFrCaleCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleCornerBr */ {KAknsIIDQsnFrCaleCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleGSideT */ {KAknsIIDQsnFrCaleSideT, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleGSideB */ {KAknsIIDQsnFrCaleSideB, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleGSideL */ {KAknsIIDQsnFrCaleSideL, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleGSideR */ {KAknsIIDQsnFrCaleSideR, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleCenter */ {KAknsIIDQsnFrCaleCenter, ENoDraw, ES60_AllReleases, -1,-1}, - - /* SP_QsnFrCaleHeadingCornerTl */ {KAknsIIDQsnFrCaleHeadingCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleHeadingCornerTr */ {KAknsIIDQsnFrCaleHeadingCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleHeadingCornerBl */ {KAknsIIDQsnFrCaleHeadingCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleHeadingCornerBr */ {KAknsIIDQsnFrCaleHeadingCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleHeadingSideT */ {KAknsIIDQsnFrCaleHeadingSideT, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleHeadingSideB */ {KAknsIIDQsnFrCaleHeadingSideB, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleHeadingSideL */ {KAknsIIDQsnFrCaleHeadingSideL, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleHeadingSideR */ {KAknsIIDQsnFrCaleHeadingSideR, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrCaleHeadingCenter */ {KAknsIIDQsnFrCaleHeadingCenter, ENoDraw, ES60_AllReleases, -1,-1}, - - /* SP_QsnFrInputCornerTl */ {KAknsIIDQsnFrInputCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrInputCornerTr */ {KAknsIIDQsnFrInputCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrInputCornerBl */ {KAknsIIDQsnFrInputCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrInputCornerBr */ {KAknsIIDQsnFrInputCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrInputSideT */ {KAknsIIDQsnFrInputSideT, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrInputSideB */ {KAknsIIDQsnFrInputSideB, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrInputSideL */ {KAknsIIDQsnFrInputSideL, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrInputSideR */ {KAknsIIDQsnFrInputSideR, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrInputCenter */ {KAknsIIDQsnFrInputCenter, ENoDraw, ES60_AllReleases, -1,-1}, - - /* SP_QsnFrListCornerTl */ {KAknsIIDQsnFrListCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrListCornerTr */ {KAknsIIDQsnFrListCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrListCornerBl */ {KAknsIIDQsnFrListCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrListCornerBr */ {KAknsIIDQsnFrListCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrListSideT */ {KAknsIIDQsnFrListSideT, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrListSideB */ {KAknsIIDQsnFrListSideB, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrListSideL */ {KAknsIIDQsnFrListSideL, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrListSideR */ {KAknsIIDQsnFrListSideR, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrListCenter */ {KAknsIIDQsnFrListCenter, ENoDraw, ES60_AllReleases, -1,-1}, - - /* SP_QsnFrPopupCornerTl */ {KAknsIIDQsnFrPopupCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrPopupCornerTr */ {KAknsIIDQsnFrPopupCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrPopupCornerBl */ {KAknsIIDQsnFrPopupCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrPopupCornerBr */ {KAknsIIDQsnFrPopupCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrPopupSideT */ {KAknsIIDQsnFrPopupSideT, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrPopupSideB */ {KAknsIIDQsnFrPopupSideB, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrPopupSideL */ {KAknsIIDQsnFrPopupSideL, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrPopupSideR */ {KAknsIIDQsnFrPopupSideR, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrPopupCenter */ {KAknsIIDQsnFrPopupCenter, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnCpScrollHandleBottomPressed*/ {KAknsIIDQsnCpScrollHandleBottom, EDrawIcon, ES60_3_X, EAknsMajorGeneric, 0x20f8}, /*KAknsIIDQsnCpScrollHandleBottomPressed*/ + /* SP_QsnCpScrollHandleMiddlePressed*/ {KAknsIIDQsnCpScrollHandleMiddle, EDrawIcon, ES60_3_X, EAknsMajorGeneric, 0x20f9}, /*KAknsIIDQsnCpScrollHandleMiddlePressed*/ + /* SP_QsnCpScrollHandleTopPressed*/ {KAknsIIDQsnCpScrollHandleTop, EDrawIcon, ES60_3_X, EAknsMajorGeneric, 0x20fa}, /*KAknsIIDQsnCpScrollHandleTopPressed*/ + + /* SP_QsnBgScreen */ {KAknsIIDQsnBgScreen, EDrawBackground, ES60_All, -1,-1}, + + /* SP_QsnCpScrollBgBottom */ {KAknsIIDQsnCpScrollBgBottom, EDrawIcon, ES60_All, -1,-1}, + /* SP_QsnCpScrollBgMiddle */ {KAknsIIDQsnCpScrollBgMiddle, EDrawIcon, ES60_All, -1,-1}, + /* SP_QsnCpScrollBgTop */ {KAknsIIDQsnCpScrollBgTop, EDrawIcon, ES60_All, -1,-1}, + + /* SP_QsnCpScrollHandleBottom */ {KAknsIIDQsnCpScrollHandleBottom, EDrawIcon, ES60_All, -1,-1}, + /* SP_QsnCpScrollHandleMiddle */ {KAknsIIDQsnCpScrollHandleMiddle, EDrawIcon, ES60_All, -1,-1}, + /* SP_QsnCpScrollHandleTop */ {KAknsIIDQsnCpScrollHandleTop, EDrawIcon, ES60_All, -1,-1}, + + /* SP_QsnFrButtonTbCornerTl */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_All, -1, -1}, + /* SP_QsnFrButtonTbCornerTr */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_All, -1, -1}, + /* SP_QsnFrButtonTbCornerBl */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_All, -1, -1}, + /* SP_QsnFrButtonTbCornerBr */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_All, -1, -1}, + /* SP_QsnFrButtonTbSideT */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_All, -1, -1}, + /* SP_QsnFrButtonTbSideB */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_All, -1, -1}, + /* SP_QsnFrButtonTbSideL */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_All, -1, -1}, + /* SP_QsnFrButtonTbSideR */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_All, -1, -1}, + /* SP_QsnFrButtonTbCenter */ {KAknsIIDQsnFrButtonTbCenter, EDrawIcon, ES60_All, -1, -1}, + + /* SP_QsnFrButtonTbCornerTlPressed */{KAknsIIDQsnFrButtonTbCornerTlPressed, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrButtonTbCornerTrPressed */{KAknsIIDQsnFrButtonTbCornerTrPressed, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrButtonTbCornerBlPressed */{KAknsIIDQsnFrButtonTbCornerBlPressed, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrButtonTbCornerBrPressed */{KAknsIIDQsnFrButtonTbCornerBrPressed, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrButtonTbSideTPressed */ {KAknsIIDQsnFrButtonTbSideTPressed, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrButtonTbSideBPressed */ {KAknsIIDQsnFrButtonTbSideBPressed, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrButtonTbSideLPressed */ {KAknsIIDQsnFrButtonTbSideLPressed, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrButtonTbSideRPressed */ {KAknsIIDQsnFrButtonTbSideRPressed, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrButtonTbCenterPressed */ {KAknsIIDQsnFrButtonTbCenterPressed, EDrawIcon, ES60_All, -1,-1}, + + /* SP_QsnFrCaleCornerTl */ {KAknsIIDQsnFrCaleCornerTl, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleCornerTr */ {KAknsIIDQsnFrCaleCornerTr, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleCornerBl */ {KAknsIIDQsnFrCaleCornerBl, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleCornerBr */ {KAknsIIDQsnFrCaleCornerBr, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleGSideT */ {KAknsIIDQsnFrCaleSideT, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleGSideB */ {KAknsIIDQsnFrCaleSideB, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleGSideL */ {KAknsIIDQsnFrCaleSideL, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleGSideR */ {KAknsIIDQsnFrCaleSideR, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleCenter */ {KAknsIIDQsnFrCaleCenter, ENoDraw, ES60_All, -1,-1}, + + /* SP_QsnFrCaleHeadingCornerTl */ {KAknsIIDQsnFrCaleHeadingCornerTl, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleHeadingCornerTr */ {KAknsIIDQsnFrCaleHeadingCornerTr, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleHeadingCornerBl */ {KAknsIIDQsnFrCaleHeadingCornerBl, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleHeadingCornerBr */ {KAknsIIDQsnFrCaleHeadingCornerBr, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleHeadingSideT */ {KAknsIIDQsnFrCaleHeadingSideT, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleHeadingSideB */ {KAknsIIDQsnFrCaleHeadingSideB, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleHeadingSideL */ {KAknsIIDQsnFrCaleHeadingSideL, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleHeadingSideR */ {KAknsIIDQsnFrCaleHeadingSideR, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrCaleHeadingCenter */ {KAknsIIDQsnFrCaleHeadingCenter, ENoDraw, ES60_All, -1,-1}, + + /* SP_QsnFrInputCornerTl */ {KAknsIIDQsnFrInputCornerTl, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrInputCornerTr */ {KAknsIIDQsnFrInputCornerTr, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrInputCornerBl */ {KAknsIIDQsnFrInputCornerBl, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrInputCornerBr */ {KAknsIIDQsnFrInputCornerBr, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrInputSideT */ {KAknsIIDQsnFrInputSideT, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrInputSideB */ {KAknsIIDQsnFrInputSideB, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrInputSideL */ {KAknsIIDQsnFrInputSideL, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrInputSideR */ {KAknsIIDQsnFrInputSideR, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrInputCenter */ {KAknsIIDQsnFrInputCenter, ENoDraw, ES60_All, -1,-1}, + + /* SP_QsnFrListCornerTl */ {KAknsIIDQsnFrListCornerTl, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrListCornerTr */ {KAknsIIDQsnFrListCornerTr, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrListCornerBl */ {KAknsIIDQsnFrListCornerBl, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrListCornerBr */ {KAknsIIDQsnFrListCornerBr, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrListSideT */ {KAknsIIDQsnFrListSideT, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrListSideB */ {KAknsIIDQsnFrListSideB, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrListSideL */ {KAknsIIDQsnFrListSideL, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrListSideR */ {KAknsIIDQsnFrListSideR, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrListCenter */ {KAknsIIDQsnFrListCenter, ENoDraw, ES60_All, -1,-1}, + + /* SP_QsnFrPopupCornerTl */ {KAknsIIDQsnFrPopupCornerTl, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrPopupCornerTr */ {KAknsIIDQsnFrPopupCornerTr, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrPopupCornerBl */ {KAknsIIDQsnFrPopupCornerBl, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrPopupCornerBr */ {KAknsIIDQsnFrPopupCornerBr, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrPopupSideT */ {KAknsIIDQsnFrPopupSideT, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrPopupSideB */ {KAknsIIDQsnFrPopupSideB, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrPopupSideL */ {KAknsIIDQsnFrPopupSideL, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrPopupSideR */ {KAknsIIDQsnFrPopupSideR, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrPopupCenter */ {KAknsIIDQsnFrPopupCenter, ENoDraw, ES60_All, -1,-1}, // ToolTip graphics different in 3.1 vs. 3.2+. - /* SP_QsnFrPopupPreviewCornerTl */ {KAknsIIDQsnFrPopupCornerTl, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c5}, /* KAknsIIDQsnFrPopupPreviewCornerTl */ - /* SP_QsnFrPopupPreviewCornerTr */ {KAknsIIDQsnFrPopupCornerTr, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c6}, - /* SP_QsnFrPopupPreviewCornerBl */ {KAknsIIDQsnFrPopupCornerBl, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c3}, - /* SP_QsnFrPopupPreviewCornerBr */ {KAknsIIDQsnFrPopupCornerBr, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c4}, - /* SP_QsnFrPopupPreviewSideT */ {KAknsIIDQsnFrPopupSideT, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19ca}, - /* SP_QsnFrPopupPreviewSideB */ {KAknsIIDQsnFrPopupSideB, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c7}, - /* SP_QsnFrPopupPreviewSideL */ {KAknsIIDQsnFrPopupSideL, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c8}, - /* SP_QsnFrPopupPreviewSideR */ {KAknsIIDQsnFrPopupSideR, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c9}, - /* SP_QsnFrPopupPreviewCenter */ {KAknsIIDQsnFrPopupCenter, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c2}, - - /* SP_QsnFrSetOptCornerTl */ {KAknsIIDQsnFrSetOptCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrSetOptCornerTr */ {KAknsIIDQsnFrSetOptCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrSetOptCornerBl */ {KAknsIIDQsnFrSetOptCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrSetOptCornerBr */ {KAknsIIDQsnFrSetOptCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrSetOptSideT */ {KAknsIIDQsnFrSetOptSideT, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrSetOptSideB */ {KAknsIIDQsnFrSetOptSideB, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrSetOptSideL */ {KAknsIIDQsnFrSetOptSideL, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrSetOptSideR */ {KAknsIIDQsnFrSetOptSideR, ENoDraw, ES60_AllReleases, -1,-1}, - /* SP_QsnFrSetOptCenter */ {KAknsIIDQsnFrSetOptCenter, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupPreviewCornerTl */ {KAknsIIDQsnFrPopupCornerTl, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c5}, /* KAknsIIDQsnFrPopupPreviewCornerTl */ + /* SP_QsnFrPopupPreviewCornerTr */ {KAknsIIDQsnFrPopupCornerTr, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c6}, + /* SP_QsnFrPopupPreviewCornerBl */ {KAknsIIDQsnFrPopupCornerBl, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c3}, + /* SP_QsnFrPopupPreviewCornerBr */ {KAknsIIDQsnFrPopupCornerBr, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c4}, + /* SP_QsnFrPopupPreviewSideT */ {KAknsIIDQsnFrPopupSideT, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19ca}, + /* SP_QsnFrPopupPreviewSideB */ {KAknsIIDQsnFrPopupSideB, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c7}, + /* SP_QsnFrPopupPreviewSideL */ {KAknsIIDQsnFrPopupSideL, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c8}, + /* SP_QsnFrPopupPreviewSideR */ {KAknsIIDQsnFrPopupSideR, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c9}, + /* SP_QsnFrPopupPreviewCenter */ {KAknsIIDQsnFrPopupCenter, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c2}, + + /* SP_QsnFrSetOptCornerTl */ {KAknsIIDQsnFrSetOptCornerTl, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrSetOptCornerTr */ {KAknsIIDQsnFrSetOptCornerTr, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrSetOptCornerBl */ {KAknsIIDQsnFrSetOptCornerBl, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrSetOptCornerBr */ {KAknsIIDQsnFrSetOptCornerBr, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrSetOptSideT */ {KAknsIIDQsnFrSetOptSideT, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrSetOptSideB */ {KAknsIIDQsnFrSetOptSideB, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrSetOptSideL */ {KAknsIIDQsnFrSetOptSideL, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrSetOptSideR */ {KAknsIIDQsnFrSetOptSideR, ENoDraw, ES60_All, -1,-1}, + /* SP_QsnFrSetOptCenter */ {KAknsIIDQsnFrSetOptCenter, ENoDraw, ES60_All, -1,-1}, // No toolbar frame for 5.0+ releases. - /* SP_QsnFrPopupSubCornerTl */ {KAknsIIDQsnFrPopupSubCornerTl, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, - /* SP_QsnFrPopupSubCornerTr */ {KAknsIIDQsnFrPopupSubCornerTr, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, - /* SP_QsnFrPopupSubCornerBl */ {KAknsIIDQsnFrPopupSubCornerBl, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, - /* SP_QsnFrPopupSubCornerBr */ {KAknsIIDQsnFrPopupSubCornerBr, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, - /* SP_QsnFrPopupSubSideT */ {KAknsIIDQsnFrPopupSubSideT, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, - /* SP_QsnFrPopupSubSideB */ {KAknsIIDQsnFrPopupSubSideB, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, - /* SP_QsnFrPopupSubSideL */ {KAknsIIDQsnFrPopupSubSideL, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, - /* SP_QsnFrPopupSubSideR */ {KAknsIIDQsnFrPopupSubSideR, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, - /* SP_QsnFrPopupSubCenter */ {KAknsIIDQsnFrPopupCenterSubmenu, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubCornerTl */ {KAknsIIDQsnFrPopupSubCornerTl, ENoDraw, ES60_3_X, -1,-1}, + /* SP_QsnFrPopupSubCornerTr */ {KAknsIIDQsnFrPopupSubCornerTr, ENoDraw, ES60_3_X, -1,-1}, + /* SP_QsnFrPopupSubCornerBl */ {KAknsIIDQsnFrPopupSubCornerBl, ENoDraw, ES60_3_X, -1,-1}, + /* SP_QsnFrPopupSubCornerBr */ {KAknsIIDQsnFrPopupSubCornerBr, ENoDraw, ES60_3_X, -1,-1}, + /* SP_QsnFrPopupSubSideT */ {KAknsIIDQsnFrPopupSubSideT, ENoDraw, ES60_3_X, -1,-1}, + /* SP_QsnFrPopupSubSideB */ {KAknsIIDQsnFrPopupSubSideB, ENoDraw, ES60_3_X, -1,-1}, + /* SP_QsnFrPopupSubSideL */ {KAknsIIDQsnFrPopupSubSideL, ENoDraw, ES60_3_X, -1,-1}, + /* SP_QsnFrPopupSubSideR */ {KAknsIIDQsnFrPopupSubSideR, ENoDraw, ES60_3_X, -1,-1}, + /* SP_QsnFrPopupSubCenter */ {KAknsIIDQsnFrPopupCenterSubmenu, ENoDraw, ES60_3_X, -1,-1}, // Toolbar graphics is different in 3.1/3.2 vs. 5.0 - /* SP_QsnFrSctrlButtonCornerTl */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2301}, /* KAknsIIDQgnFrSctrlButtonCornerTl*/ - /* SP_QsnFrSctrlButtonCornerTr */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2302}, - /* SP_QsnFrSctrlButtonCornerBl */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2303}, - /* SP_QsnFrSctrlButtonCornerBr */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2304}, - /* SP_QsnFrSctrlButtonSideT */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2305}, - /* SP_QsnFrSctrlButtonSideB */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2306}, - /* SP_QsnFrSctrlButtonSideL */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2307}, - /* SP_QsnFrSctrlButtonSideR */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2308}, - /* SP_QsnFrSctrlButtonCenter */ {KAknsIIDQsnFrButtonTbCenter, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2309}, /*KAknsIIDQgnFrSctrlButtonCenter*/ + /* SP_QsnFrSctrlButtonCornerTl */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2301}, /* KAknsIIDQgnFrSctrlButtonCornerTl*/ + /* SP_QsnFrSctrlButtonCornerTr */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2302}, + /* SP_QsnFrSctrlButtonCornerBl */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2303}, + /* SP_QsnFrSctrlButtonCornerBr */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2304}, + /* SP_QsnFrSctrlButtonSideT */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2305}, + /* SP_QsnFrSctrlButtonSideB */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2306}, + /* SP_QsnFrSctrlButtonSideL */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2307}, + /* SP_QsnFrSctrlButtonSideR */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2308}, + /* SP_QsnFrSctrlButtonCenter */ {KAknsIIDQsnFrButtonTbCenter, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2309}, /*KAknsIIDQgnFrSctrlButtonCenter*/ // No pressed state for toolbar button in 3.1/3.2. - /* SP_QsnFrSctrlButtonCornerTlPressed */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2621}, /*KAknsIIDQsnFrSctrlButtonCornerTlPressed*/ - /* SP_QsnFrSctrlButtonCornerTrPressed */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2622}, - /* SP_QsnFrSctrlButtonCornerBlPressed */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2623}, - /* SP_QsnFrSctrlButtonCornerBrPressed */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2624}, - /* SP_QsnFrSctrlButtonSideTPressed */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2625}, - /* SP_QsnFrSctrlButtonSideBPressed */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2626}, - /* SP_QsnFrSctrlButtonSideLPressed */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2627}, - /* SP_QsnFrSctrlButtonSideRPressed */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2628}, - /* SP_QsnFrSctrlButtonCenterPressed */ {KAknsIIDQsnFrButtonTbCenter, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2629}, + /* SP_QsnFrSctrlButtonCornerTlPressed */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2621}, /*KAknsIIDQsnFrSctrlButtonCornerTlPressed*/ + /* SP_QsnFrSctrlButtonCornerTrPressed */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2622}, + /* SP_QsnFrSctrlButtonCornerBlPressed */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2623}, + /* SP_QsnFrSctrlButtonCornerBrPressed */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2624}, + /* SP_QsnFrSctrlButtonSideTPressed */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2625}, + /* SP_QsnFrSctrlButtonSideBPressed */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2626}, + /* SP_QsnFrSctrlButtonSideLPressed */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2627}, + /* SP_QsnFrSctrlButtonSideRPressed */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2628}, + /* SP_QsnFrSctrlButtonCenterPressed */ {KAknsIIDQsnFrButtonTbCenter, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x2629}, // No inactive button graphics in 3.1/3.2 - /* SP_QsnFrButtonCornerTlInactive */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b1}, /*KAknsIIDQsnFrButtonCornerTlInactive*/ - /* SP_QsnFrButtonCornerTrInactive */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b2}, - /* SP_QsnFrButtonCornerBlInactive */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b3}, - /* SP_QsnFrButtonCornerTrInactive */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b4}, - /* SP_QsnFrButtonSideTInactive */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b5}, - /* SP_QsnFrButtonSideBInactive */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b6}, - /* SP_QsnFrButtonSideLInactive */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b7}, - /* SP_QsnFrButtonSideRInactive */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b8}, - /* SP_QsnFrButtonCenterInactive */ {KAknsIIDQsnFrButtonTbCenter, EDrawIcon, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b9}, + /* SP_QsnFrButtonCornerTlInactive */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x21b1}, /*KAknsIIDQsnFrButtonCornerTlInactive*/ + /* SP_QsnFrButtonCornerTrInactive */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x21b2}, + /* SP_QsnFrButtonCornerBlInactive */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x21b3}, + /* SP_QsnFrButtonCornerTrInactive */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x21b4}, + /* SP_QsnFrButtonSideTInactive */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x21b5}, + /* SP_QsnFrButtonSideBInactive */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x21b6}, + /* SP_QsnFrButtonSideLInactive */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x21b7}, + /* SP_QsnFrButtonSideRInactive */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_3_X, EAknsMajorSkin, 0x21b8}, + /* SP_QsnFrButtonCenterInactive */ {KAknsIIDQsnFrButtonTbCenter, EDrawIcon, ES60_3_X, EAknsMajorSkin, 0x21b9}, }; @@ -349,7 +360,7 @@ QPixmap QS60StyleModeSpecifics::skinnedGraphics( } QPixmap QS60StyleModeSpecifics::colorSkinnedGraphics( - const QS60StyleEnums::SkinParts &stylepart, const QSize &size, QPainter *painter, + const QS60StyleEnums::SkinParts &stylepart, const QSize &size, QPainter *painter, QS60StylePrivate::SkinElementFlags flags) { QPixmap colorGraphics; @@ -357,155 +368,121 @@ QPixmap QS60StyleModeSpecifics::colorSkinnedGraphics( return error ? QPixmap() : colorGraphics; } -void QS60StyleModeSpecifics::fallbackInfo(const QS60StyleEnums::SkinParts &stylepart, TDes& fallbackFileName, TInt& fallbackIndex) +void QS60StyleModeSpecifics::fallbackInfo(const QS60StyleEnums::SkinParts &stylePart, TInt &fallbackIndex) { - switch(stylepart) { + switch(stylePart) { case QS60StyleEnums::SP_QgnGrafBarWait: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_graf_bar_wait_1; break; case QS60StyleEnums::SP_QgnGrafBarFrameCenter: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_graf_bar_frame_center; break; case QS60StyleEnums::SP_QgnGrafBarFrameSideL: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_graf_bar_frame_side_l; break; case QS60StyleEnums::SP_QgnGrafBarFrameSideR: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_graf_bar_frame_side_r; break; case QS60StyleEnums::SP_QgnGrafBarProgress: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_graf_bar_progress; break; case QS60StyleEnums::SP_QgnGrafTabActiveL: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_graf_tab_active_l; break; case QS60StyleEnums::SP_QgnGrafTabActiveM: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_graf_tab_active_m; break; case QS60StyleEnums::SP_QgnGrafTabActiveR: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_graf_tab_active_r; break; case QS60StyleEnums::SP_QgnGrafTabPassiveL: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_graf_tab_passive_l; break; case QS60StyleEnums::SP_QgnGrafTabPassiveM: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_graf_tab_passive_m; break; case QS60StyleEnums::SP_QgnGrafTabPassiveR: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_graf_tab_passive_r; break; case QS60StyleEnums::SP_QgnIndiCheckboxOff: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_indi_checkbox_off; break; case QS60StyleEnums::SP_QgnIndiCheckboxOn: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_indi_checkbox_on; break; case QS60StyleEnums::SP_QgnIndiHlColSuper: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = 0x4456; /* EMbmAvkonQgn_indi_hl_col_super */ break; case QS60StyleEnums::SP_QgnIndiHlExpSuper: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = 0x4458; /* EMbmAvkonQgn_indi_hl_exp_super */ break; case QS60StyleEnums::SP_QgnIndiHlLineBranch: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = 0x445A; /* EMbmAvkonQgn_indi_hl_line_branch */ break; case QS60StyleEnums::SP_QgnIndiHlLineEnd: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = 0x445C; /* EMbmAvkonQgn_indi_hl_line_end */ break; case QS60StyleEnums::SP_QgnIndiHlLineStraight: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = 0x445E; /* EMbmAvkonQgn_indi_hl_line_straight */ break; case QS60StyleEnums::SP_QgnIndiMarkedAdd: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_indi_marked_add; break; case QS60StyleEnums::SP_QgnIndiNaviArrowLeft: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_indi_navi_arrow_left; break; case QS60StyleEnums::SP_QgnIndiNaviArrowRight: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_indi_navi_arrow_right; break; case QS60StyleEnums::SP_QgnIndiRadiobuttOff: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_indi_radiobutt_off; break; case QS60StyleEnums::SP_QgnIndiRadiobuttOn: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_indi_radiobutt_on; break; - case QS60StyleEnums::SP_QgnIndiSliderEdit: - fallbackFileName = KAvkonBitmapFile(); - fallbackIndex = EMbmAvkonQgn_indi_slider_edit; + case QS60StyleEnums::SP_QgnGrafNsliderMarker: + fallbackIndex = 17572; /* EMbmAvkonQgn_graf_nslider_marker */ + break; + case QS60StyleEnums::SP_QgnGrafNsliderMarkerSelected: + fallbackIndex = 17574; /* EMbmAvkonQgn_graf_nslider_marker_selected */ break; case QS60StyleEnums::SP_QgnIndiSubMenu: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_indi_submenu; break; case QS60StyleEnums::SP_QgnNoteErased: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_note_erased; break; case QS60StyleEnums::SP_QgnNoteError: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_note_error; break; case QS60StyleEnums::SP_QgnNoteInfo: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_note_info; break; case QS60StyleEnums::SP_QgnNoteOk: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_note_ok; break; case QS60StyleEnums::SP_QgnNoteQuery: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_note_query; break; case QS60StyleEnums::SP_QgnNoteWarning: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_note_warning; break; case QS60StyleEnums::SP_QgnPropFileSmall: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_prop_file_small; break; case QS60StyleEnums::SP_QgnPropFolderCurrent: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_prop_folder_current; break; case QS60StyleEnums::SP_QgnPropFolderSmall: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_prop_folder_small; break; case QS60StyleEnums::SP_QgnPropFolderSmallNew: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_prop_folder_small_new; break; case QS60StyleEnums::SP_QgnPropPhoneMemcLarge: - fallbackFileName = KAvkonBitmapFile(); fallbackIndex = EMbmAvkonQgn_prop_phone_memc_large; break; default: - fallbackFileName = KNullDesC(); fallbackIndex = -1; break; } @@ -521,8 +498,7 @@ QPixmap QS60StyleModeSpecifics::colorSkinnedGraphicsLX( TInt fallbackGraphicID = -1; HBufC* iconFile = HBufC::NewLC( KMaxFileName ); - TPtr fileNamePtr = iconFile->Des(); - fallbackInfo(stylepart, fileNamePtr, fallbackGraphicID); + fallbackInfo(stylepart, fallbackGraphicID); TAknsItemID colorGroup = KAknsIIDQsnIconColors; TRgb defaultColor = KRgbBlack; @@ -543,10 +519,18 @@ QPixmap QS60StyleModeSpecifics::colorSkinnedGraphicsLX( fallbackGraphicID == KErrNotFound?KErrNotFound:fallbackGraphicID+1; //masks are auto-generated as next in mif files MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance(); AknsUtils::CreateColorIconLC( - skinInstance, skinId, colorGroup, colorIndex, icon, iconMask, fileNamePtr, fallbackGraphicID , fallbackGraphicsMaskID, defaultColor); - User::LeaveIfError(AknIconUtils::SetSize(icon, targetSize, EAspectRatioNotPreserved)); - User::LeaveIfError(AknIconUtils::SetSize(iconMask, targetSize, EAspectRatioNotPreserved)); - QPixmap result = fromFbsBitmap(icon, iconMask, flags, qt_TDisplayMode2Format(icon->DisplayMode())); + skinInstance, + skinId, + colorGroup, + colorIndex, + icon, + iconMask, + AknIconUtils::AvkonIconFileName(), + fallbackGraphicID, + fallbackGraphicsMaskID, + defaultColor); + + QPixmap result = fromFbsBitmap(icon, iconMask, flags, targetSize); CleanupStack::PopAndDestroy(3); //icon, iconMask, iconFile return result; } @@ -566,55 +550,43 @@ struct QAutoFbsBitmapHeapLock CFbsBitmap* mBmp; }; -QPixmap QS60StyleModeSpecifics::fromFbsBitmap(CFbsBitmap *icon, CFbsBitmap *mask, QS60StylePrivate::SkinElementFlags flags, QImage::Format format) +QPixmap QS60StyleModeSpecifics::fromFbsBitmap(CFbsBitmap *icon, CFbsBitmap *mask, QS60StylePrivate::SkinElementFlags flags, const TSize &targetSize) { Q_ASSERT(icon); - const TSize iconSize = icon->SizeInPixels(); - const int iconBytesPerLine = CFbsBitmap::ScanLineLength(iconSize.iWidth, icon->DisplayMode()); - const int iconBytesCount = iconBytesPerLine * iconSize.iHeight; - QImage iconImage(qt_TSize2QSize(iconSize), format); - if (iconImage.isNull()) - return QPixmap(); + AknIconUtils::DisableCompression(icon); + TInt error = AknIconUtils::SetSize(icon, targetSize, EAspectRatioNotPreserved); - checkAndUnCompressBitmap(icon); - if (!icon) //checkAndUnCompressBitmap might set icon to NULL + if (mask && !error) { + AknIconUtils::DisableCompression(mask); + error = AknIconUtils::SetSize(mask, targetSize, EAspectRatioNotPreserved); + } + if (error) return QPixmap(); - icon->LockHeap(); - const uchar *const iconBytes = (uchar*)icon->DataAddress(); - // The icon data needs to be copied, since the color format will be - // automatically converted to Format_ARGB32 when setAlphaChannel is called. - memcpy(iconImage.bits(), iconBytes, iconBytesCount); - icon->UnlockHeap(); - if (mask) { - checkAndUnCompressBitmap(mask); - if (mask) { //checkAndUnCompressBitmap might set mask to NULL - const TSize maskSize = icon->SizeInPixels(); - const int maskBytesPerLine = CFbsBitmap::ScanLineLength(maskSize.iWidth, mask->DisplayMode()); - // heap lock object required because QImage ctor might throw - QAutoFbsBitmapHeapLock maskHeapLock(mask); - const uchar *const maskBytes = (uchar *)mask->DataAddress(); - // Since no other bitmap should be locked, we can just "borrow" the mask data for setAlphaChannel - const QImage maskImage(maskBytes, maskSize.iWidth, maskSize.iHeight, maskBytesPerLine, QImage::Format_Indexed8); - if (!maskImage.isNull()) - iconImage.setAlphaChannel(maskImage); + QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(icon); + if (mask) + pixmap.setAlphaChannel(QPixmap::fromSymbianCFbsBitmap(mask)); + + if ((flags & QS60StylePrivate::SF_PointEast) || + (flags & QS60StylePrivate::SF_PointSouth) || + (flags & QS60StylePrivate::SF_PointWest)) { + QImage iconImage = pixmap.toImage(); + QTransform imageTransform; + if (flags & QS60StylePrivate::SF_PointEast) { + imageTransform.rotate(90); + } else if (flags & QS60StylePrivate::SF_PointSouth) { + imageTransform.rotate(180); + iconImage = iconImage.transformed(imageTransform); + } else if (flags & QS60StylePrivate::SF_PointWest) { + imageTransform.rotate(270); } - } + if (imageTransform.isRotating()) + iconImage = iconImage.transformed(imageTransform); - QTransform imageTransform; - if (flags & QS60StylePrivate::SF_PointEast) { - imageTransform.rotate(90); - } else if (flags & QS60StylePrivate::SF_PointSouth) { - imageTransform.rotate(180); - iconImage = iconImage.transformed(imageTransform); - } else if (flags & QS60StylePrivate::SF_PointWest) { - imageTransform.rotate(270); + pixmap = QPixmap::fromImage(iconImage); } - if (imageTransform.isRotating()) - iconImage = iconImage.transformed(imageTransform); - - return QPixmap::fromImage(iconImage); + return pixmap; } bool QS60StylePrivate::isTouchSupported() @@ -627,6 +599,11 @@ bool QS60StylePrivate::isToolBarBackground() return (QSysInfo::s60Version() == QSysInfo::SV_S60_3_1 || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2); } +bool QS60StylePrivate::hasSliderGrooveGraphic() +{ + return QSysInfo::s60Version() != QSysInfo::SV_S60_3_1; +} + QPoint qt_s60_fill_background_offset(const QWidget *targetWidget) { CCoeControl *control = targetWidget->effectiveWinId(); @@ -645,7 +622,7 @@ QPoint qt_s60_fill_background_offset(const QWidget *targetWidget) } QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX( - QS60StyleEnums::SkinParts part, const QSize &size, + QS60StyleEnums::SkinParts part, const QSize &size, QS60StylePrivate::SkinElementFlags flags) { // this function can throw both exceptions and leaves. There are no cleanup dependencies between Qt and Symbian parts. @@ -653,7 +630,7 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX( return QPixmap(); // Check release support and change part, if necessary. - const TAknsItemID skinId = checkAndUpdateReleaseSpecificGraphics((int)part); + const TAknsItemID skinId = partSpecificThemeId((int)part); const int stylepartIndex = (int)part; const TDrawType drawType = m_partMap[stylepartIndex].drawType; Q_ASSERT(drawType != ENoDraw); @@ -667,24 +644,34 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX( QPixmap result; switch (drawType) { + case EDrawGulIcon: { + CGulIcon* icon = AknsUtils::CreateGulIconL( AknsUtils::SkinInstance(), skinId, EFalse ); + if (icon) + result = fromFbsBitmap(icon->Bitmap(), icon->Mask(), flags, targetSize); + delete icon; + break; + } case EDrawIcon: { TInt fallbackGraphicID = -1; - HBufC* iconFile = HBufC::NewLC( KMaxFileName ); - TPtr fileNamePtr = iconFile->Des(); - fallbackInfo(part, fileNamePtr, fallbackGraphicID); - // todo: could we instead use AknIconUtils::AvkonIconFileName(); to avoid allocating each time? + fallbackInfo(part, fallbackGraphicID); CFbsBitmap *icon = 0; CFbsBitmap *iconMask = 0; const TInt fallbackGraphicsMaskID = fallbackGraphicID == KErrNotFound?KErrNotFound:fallbackGraphicID+1; //masks are auto-generated as next in mif files - // QS60WindowSurface::unlockBitmapHeap(); - AknsUtils::CreateIconLC(skinInstance, skinId, icon, iconMask, fileNamePtr, fallbackGraphicID , fallbackGraphicsMaskID); - User::LeaveIfError(AknIconUtils::SetSize(icon, targetSize, EAspectRatioNotPreserved)); - User::LeaveIfError(AknIconUtils::SetSize(iconMask, targetSize, EAspectRatioNotPreserved)); - result = fromFbsBitmap(icon, iconMask, flags, qt_TDisplayMode2Format(icon->DisplayMode())); - CleanupStack::PopAndDestroy(3); // iconMask, icon, iconFile - // QS60WindowSurface::lockBitmapHeap(); + + AknsUtils::CreateIconL( + skinInstance, + skinId, + icon, + iconMask, + AknIconUtils::AvkonIconFileName(), + fallbackGraphicID , + fallbackGraphicsMaskID); + + result = fromFbsBitmap(icon, iconMask, flags, targetSize); + delete icon; + delete iconMask; break; } case EDrawBackground: { @@ -715,13 +702,16 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX( KAknsDrawParamDefault | KAknsDrawParamRGBOnly); if (drawn) - result = fromFbsBitmap(background, NULL, flags, QImage::Format_RGB32); + result = fromFbsBitmap(background, NULL, flags, targetSize); + // if drawing fails in skin server, just ignore the background (probably OOM occured) CleanupStack::PopAndDestroy(4, background); //background, dev, gc, bgContext // QS60WindowSurface::lockBitmapHeap(); break; } } + if (!result) + result = QPixmap(); return result; } @@ -755,24 +745,46 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX(QS60StylePrivate::SkinFr User::LeaveIfError(bitmapDev->CreateContext(bitmapGc)); CleanupStack::PushL(bitmapGc); +#ifndef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE frame->LockHeap(); memset(frame->DataAddress(), 0, frame->SizeInPixels().iWidth * frame->SizeInPixels().iHeight * 4); // 4: argb bytes frame->UnlockHeap(); +#endif const TRect outerRect(TPoint(0, 0), targetSize); const TRect innerRect = innerRectFromElement(frameElement, outerRect); TAknsItemID frameSkinID, centerSkinID; - frameSkinID = centerSkinID = checkAndUpdateReleaseSpecificGraphics(QS60StylePrivate::m_frameElementsData[frameElement].center); + frameSkinID = centerSkinID = partSpecificThemeId(QS60StylePrivate::m_frameElementsData[frameElement].center); frameIdAndCenterId(frameElement, frameSkinID, centerSkinID); - const TBool drawn = AknsDrawUtils::DrawFrame( skinInstance, - *bitmapGc, outerRect, innerRect, - frameSkinID, centerSkinID, - drawParam ); + + TBool drawn = AknsDrawUtils::DrawFrame( + skinInstance, + *bitmapGc, + outerRect, + innerRect, + frameSkinID, + centerSkinID, + drawParam ); if (S60->supportsPremultipliedAlpha) { - if (drawn) - result = fromFbsBitmap(frame, NULL, flags, QImage::Format_ARGB32_Premultiplied); + if (drawn) { + result = fromFbsBitmap(frame, NULL, flags, targetSize); + } else { + // Drawing might fail due to OOM (we can do nothing about that), + // or due to skin item not being available. + // If the latter occurs, lets try switch to non-release specific items (if available) + // and re-try the drawing. + frameSkinID = centerSkinID = m_partMap[(int)QS60StylePrivate::m_frameElementsData[frameElement].center].skinID; + frameIdAndCenterId(frameElement, frameSkinID, centerSkinID); + drawn = AknsDrawUtils::DrawFrame( skinInstance, + *bitmapGc, outerRect, innerRect, + frameSkinID, centerSkinID, + drawParam ); + // in case drawing fails, even after using default graphics, ignore the error + if (drawn) + result = fromFbsBitmap(frame, NULL, flags, targetSize); + } } else { TDisplayMode maskDepth = EGray2; // Query the skin item for possible frame graphics mask details. @@ -802,11 +814,12 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX(QS60StylePrivate::SkinFr maskBitGc->Clear(); maskBitGc->SetBrushStyle(CGraphicsContext::ENullBrush); - AknsDrawUtils::DrawFrame(skinInstance, + drawn = AknsDrawUtils::DrawFrame(skinInstance, *maskBitGc, outerRect, innerRect, frameSkinID, centerSkinID, KAknsSDMAlphaOnly |KAknsDrawParamNoClearUnderImage); - result = fromFbsBitmap(frame, frameMask, flags, QImage::Format_ARGB32); + if (drawn) + result = fromFbsBitmap(frame, frameMask, flags, targetSize); } CleanupStack::PopAndDestroy(3, frameMask); } @@ -880,10 +893,12 @@ bool QS60StyleModeSpecifics::checkSupport(const int supportedRelease) const QSysInfo::S60Version currentRelease = QSysInfo::s60Version(); return ( (currentRelease == QSysInfo::SV_S60_3_1 && supportedRelease & ES60_3_1) || (currentRelease == QSysInfo::SV_S60_3_2 && supportedRelease & ES60_3_2) || - (currentRelease == QSysInfo::SV_S60_5_0 && supportedRelease & ES60_5_0)); + (currentRelease == QSysInfo::SV_S60_5_0 && supportedRelease & ES60_5_0) || + (currentRelease == QSysInfo::SV_S60_5_1 && supportedRelease & ES60_5_1) || + (currentRelease == QSysInfo::SV_S60_5_2 && supportedRelease & ES60_5_2)); } -TAknsItemID QS60StyleModeSpecifics::checkAndUpdateReleaseSpecificGraphics(int part) +TAknsItemID QS60StyleModeSpecifics::partSpecificThemeId(int part) { TAknsItemID newSkinId; if (!checkSupport(m_partMap[(int)part].supportInfo)) @@ -893,33 +908,6 @@ TAknsItemID QS60StyleModeSpecifics::checkAndUpdateReleaseSpecificGraphics(int pa return newSkinId; } -void QS60StyleModeSpecifics::checkAndUnCompressBitmap(CFbsBitmap*& aOriginalBitmap) -{ - TRAPD(error, checkAndUnCompressBitmapL(aOriginalBitmap)); - if (error) - aOriginalBitmap = NULL; -} - -void QS60StyleModeSpecifics::checkAndUnCompressBitmapL(CFbsBitmap*& aOriginalBitmap) -{ - const TSize iconSize = aOriginalBitmap->SizeInPixels(); - const int iconBytesPerLine = CFbsBitmap::ScanLineLength(iconSize.iWidth, aOriginalBitmap->DisplayMode()); - const int iconBytesCount = iconBytesPerLine * iconSize.iHeight; - if (aOriginalBitmap->IsCompressedInRAM() || aOriginalBitmap->Header().iBitmapSize < iconBytesCount) { - const TSize iconSize(aOriginalBitmap->SizeInPixels().iWidth, - aOriginalBitmap->SizeInPixels().iHeight); - CFbsBitmap* uncompressedBitmap = new (ELeave) CFbsBitmap(); - CleanupStack::PushL(uncompressedBitmap); - User::LeaveIfError(uncompressedBitmap->Create(iconSize, - aOriginalBitmap->DisplayMode())); - unCompressBitmapL(iconSize, uncompressedBitmap, aOriginalBitmap); - CleanupStack::Pop(uncompressedBitmap); - User::LeaveIfError(aOriginalBitmap->Duplicate( - uncompressedBitmap->Handle())); - delete uncompressedBitmap; - } -} - QFont QS60StylePrivate::s60Font_specific( QS60StyleEnums::FontCategories fontCategory, int pointSize) { @@ -972,37 +960,23 @@ void QS60StylePrivate::setActiveLayout() { const QSize activeScreenSize(screenSize()); int activeLayoutIndex = -1; - const bool mirrored = !QApplication::isLeftToRight(); const short screenHeight = (short)activeScreenSize.height(); const short screenWidth = (short)activeScreenSize.width(); for (int i=0; i<m_numberOfLayouts; i++) { if (screenHeight==m_layoutHeaders[i].height && - screenWidth==m_layoutHeaders[i].width && - mirrored==m_layoutHeaders[i].mirroring) { + screenWidth==m_layoutHeaders[i].width) { activeLayoutIndex = i; break; } } - //not found, lets try without mirroring info - if (activeLayoutIndex==-1){ - for (int i=0; i<m_numberOfLayouts; i++) { - if (screenHeight==m_layoutHeaders[i].height && - screenWidth==m_layoutHeaders[i].width) { - activeLayoutIndex = i; - break; - } - } - } - //not found, lets try with either of dimensions if (activeLayoutIndex==-1){ const QSysInfo::S60Version currentRelease = QSysInfo::s60Version(); const bool landscape = screenHeight < screenWidth; - activeLayoutIndex = (currentRelease == QSysInfo::SV_S60_3_1 || currentRelease == QSysInfo::SV_S60_3_2) ? 0 : 4; - activeLayoutIndex += (!landscape) ? 2 : 0; - activeLayoutIndex += (!mirrored) ? 1 : 0; + activeLayoutIndex = (currentRelease == QSysInfo::SV_S60_3_1 || currentRelease == QSysInfo::SV_S60_3_2) ? 0 : 2; + activeLayoutIndex += (!landscape) ? 1 : 0; } m_pmPointer = data[activeLayoutIndex]; @@ -1159,160 +1133,29 @@ QPixmap QS60StylePrivate::frame(SkinFrameElements frame, const QSize &size, Skin QPixmap QS60StylePrivate::backgroundTexture() { + bool createNewBackground = false; if (!m_background) { + createNewBackground = true; + } else { + //if background brush does not match screensize, re-create it + if (m_background->width() != S60->screenWidthInPixels || + m_background->height() != S60->screenHeightInPixels) { + delete m_background; + createNewBackground = true; + } + } + + if (createNewBackground) { QPixmap background = part(QS60StyleEnums::SP_QsnBgScreen, - QSize(S60->screenWidthInPixels, S60->screenHeightInPixels), 0, SkinElementFlags()); + QSize(S60->screenWidthInPixels, S60->screenHeightInPixels), 0, SkinElementFlags()); m_background = new QPixmap(background); } return *m_background; } -// If the public SDK returns compressed images, please let us also uncompress those! -void QS60StyleModeSpecifics::unCompressBitmapL(const TRect& aTrgRect, CFbsBitmap* aTrgBitmap, CFbsBitmap* aSrcBitmap) -{ - if (!aSrcBitmap) - User::Leave(KErrArgument); - if (!aTrgBitmap) - User::Leave(KErrArgument); - - // Note! aSrcBitmap->IsCompressedInRAM() is always ETrue, since this method is called only if that applies! - // Extra note! this function is also being used when bitmaps appear to be compressed (because DataSize is too small) - // even when they pretend they are not. Assert removed. -// ASSERT(aSrcBitmap->IsCompressedInRAM()); - - TDisplayMode displayMode = aSrcBitmap->DisplayMode(); - - if (displayMode != aTrgBitmap->DisplayMode()) - User::Leave(KErrArgument); - - const TSize trgSize = aTrgBitmap->SizeInPixels(); - const TSize srcSize = aSrcBitmap->SizeInPixels(); - - // calculate the valid drawing area - TRect drawRect = aTrgRect; - drawRect.Intersection(TRect(TPoint(0, 0), trgSize)); - - if (drawRect.IsEmpty()) - return; - - CFbsBitmap* realSource = new (ELeave) CFbsBitmap(); - CleanupStack::PushL(realSource); - User::LeaveIfError(realSource->Create(srcSize, displayMode)); - CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(realSource); - CleanupStack::PushL(dev); - CFbsBitGc* gc = NULL; - User::LeaveIfError(dev->CreateContext(gc)); - CleanupStack::PushL(gc); - gc->BitBlt(TPoint(0, 0), aSrcBitmap); - CleanupStack::PopAndDestroy(2); // dev, gc - - // Heap lock for FBServ large chunk is only needed with large bitmaps. - if (realSource->IsLargeBitmap() || aTrgBitmap->IsLargeBitmap()) { - aTrgBitmap->LockHeapLC(ETrue); // fbsheaplock - } else { - CleanupStack::PushL((TAny*) NULL); - } - - TUint32* srcAddress = realSource->DataAddress(); - TUint32* trgAddress = aTrgBitmap->DataAddress(); - - const TInt xSkip = (srcSize.iWidth << 8) / aTrgRect.Width(); - const TInt ySkip = (srcSize.iHeight << 8) / aTrgRect.Height(); - - const TInt drawWidth = drawRect.Width(); - const TInt drawHeight = drawRect.Height(); - - const TRect offsetRect(aTrgRect.iTl, drawRect.iTl); - const TInt yPosOffset = ySkip * offsetRect.Height(); - const TInt xPosOffset = xSkip * offsetRect.Width(); - - if ((displayMode == EGray256) || (displayMode == EColor256)) { - const TInt srcScanLen8 = CFbsBitmap::ScanLineLength(srcSize.iWidth, - displayMode); - const TInt trgScanLen8 = CFbsBitmap::ScanLineLength(trgSize.iWidth, - displayMode); - - TUint8* trgAddress8 = reinterpret_cast<TUint8*> (trgAddress); - - TInt yPos = yPosOffset; - // skip left and top margins in the beginning - trgAddress8 += trgScanLen8 * drawRect.iTl.iY + drawRect.iTl.iX; - - for (TInt y = 0; y < drawHeight; y++) { - const TUint8* srcAddress8 = reinterpret_cast<const TUint8*> (srcAddress) - + (srcScanLen8 * (yPos >> 8)); - - TInt xPos = xPosOffset; - for (TInt x = 0; x < drawWidth; x++) { - *(trgAddress8++) = srcAddress8[xPos >> 8]; - xPos += xSkip; - } - - yPos += ySkip; - - trgAddress8 += trgScanLen8 - drawWidth; - } - } else if (displayMode == EColor4K || displayMode == EColor64K) { - const TInt srcScanLen16 = CFbsBitmap::ScanLineLength(srcSize.iWidth, - displayMode) >>1; - const TInt trgScanLen16 = CFbsBitmap::ScanLineLength(trgSize.iWidth, - displayMode) >>1; - - TUint16* trgAddress16 = reinterpret_cast<TUint16*> (trgAddress); - - TInt yPos = yPosOffset; - // skip left and top margins in the beginning - trgAddress16 += trgScanLen16 * drawRect.iTl.iY + drawRect.iTl.iX; - - for (TInt y = 0; y < drawHeight; y++) { - const TUint16* srcAddress16 = reinterpret_cast<const TUint16*> (srcAddress) - + (srcScanLen16 * (yPos >> 8)); - - TInt xPos = xPosOffset; - for (TInt x = 0; x < drawWidth; x++) { - *(trgAddress16++) = srcAddress16[xPos >> 8]; - xPos += xSkip; - } - - yPos += ySkip; - - trgAddress16 += trgScanLen16 - drawWidth; - } - } else if (displayMode == EColor16MU || displayMode == EColor16MA) { - const TInt srcScanLen32 = CFbsBitmap::ScanLineLength(srcSize.iWidth, - displayMode) >>2; - const TInt trgScanLen32 = CFbsBitmap::ScanLineLength(trgSize.iWidth, - displayMode) >>2; - - TUint32* trgAddress32 = reinterpret_cast<TUint32*> (trgAddress); - - TInt yPos = yPosOffset; - // skip left and top margins in the beginning - trgAddress32 += trgScanLen32 * drawRect.iTl.iY + drawRect.iTl.iX; - - for (TInt y = 0; y < drawHeight; y++) { - const TUint32* srcAddress32 = reinterpret_cast<const TUint32*> (srcAddress) - + (srcScanLen32 * (yPos >> 8)); - - TInt xPos = xPosOffset; - for (TInt x = 0; x < drawWidth; x++) { - *(trgAddress32++) = srcAddress32[xPos >> 8]; - xPos += xSkip; - } - - yPos += ySkip; - - trgAddress32 += trgScanLen32 - drawWidth; - } - } else { User::Leave(KErrUnknown);} - - CleanupStack::PopAndDestroy(2); // fbsheaplock, realSource -} - QSize QS60StylePrivate::screenSize() { - const TSize screenSize = QS60Data::screenDevice()->SizeInPixels(); - return QSize(screenSize.iWidth, screenSize.iHeight); + return QSize(S60->screenWidthInPixels, S60->screenHeightInPixels); } QS60Style::QS60Style() diff --git a/src/gui/styles/qs60style_simulated.cpp b/src/gui/styles/qs60style_simulated.cpp index 55d5771..e49854f 100644 --- a/src/gui/styles/qs60style_simulated.cpp +++ b/src/gui/styles/qs60style_simulated.cpp @@ -337,6 +337,11 @@ bool QS60StylePrivate::isToolBarBackground() return true; } +bool QS60StylePrivate::hasSliderGrooveGraphic() +{ + return false; +} + QFont QS60StylePrivate::s60Font_specific(QS60StyleEnums::FontCategories fontCategory, int pointSize) { QFont result; diff --git a/src/gui/styles/qstylehelper.cpp b/src/gui/styles/qstylehelper.cpp index af30f15..f5af960 100644 --- a/src/gui/styles/qstylehelper.cpp +++ b/src/gui/styles/qstylehelper.cpp @@ -154,7 +154,7 @@ qreal angle(const QPointF &p1, const QPointF &p2) } qreal m = -(y2 - y1) / (x2 - x1); - _angle = atan(m) * rad_factor; + _angle = qAtan(m) * rad_factor; if (p1.x() < p2.x()) _angle = 180 - _angle; diff --git a/src/gui/styles/styles.pri b/src/gui/styles/styles.pri index 88a2cce..7e5c55a 100644 --- a/src/gui/styles/styles.pri +++ b/src/gui/styles/styles.pri @@ -168,7 +168,7 @@ contains( styles, s60 ):contains(QT_CONFIG, s60) { SOURCES += styles/qs60style.cpp symbian { SOURCES += styles/qs60style_s60.cpp - LIBS += -laknicon -laknskins -laknskinsrv -lfontutils + LIBS += -laknicon -laknskins -laknskinsrv -lfontutils -legul } else { SOURCES += styles/qs60style_simulated.cpp RESOURCES += styles/qstyle_s60_simulated.qrc diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 7e93aa0..e9c7b89 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -1482,13 +1482,13 @@ QString QFontDatabase::styleString(const QFontInfo &fontInfo) and style will look attractive. If the font family is available from two or more foundries the - foundry name is included in the family name, e.g. "Helvetica - [Adobe]" and "Helvetica [Cronyx]". When you specify a family you - can either use the old hyphenated Qt 2.x "foundry-family" format, - e.g. "Cronyx-Helvetica", or the new bracketed Qt 3.x "family - [foundry]" format e.g. "Helvetica [Cronyx]". If the family has a - foundry it is always returned, e.g. by families(), using the - bracketed format. + foundry name is included in the family name; for example: + "Helvetica [Adobe]" and "Helvetica [Cronyx]". When you specify a + family, you can either use the old hyphenated "foundry-family" + format or the bracketed "family [foundry]" format; for example: + "Cronyx-Helvetica" or "Helvetica [Cronyx]". If the family has a + foundry it is always returned using the bracketed format, as is + the case with the value returned by families(). The font() function returns a QFont given a family, style and point size. diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 27fc3c1..d364025 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -185,22 +185,11 @@ QFontEngine::QFontEngine() QFontEngine::~QFontEngine() { - for (GlyphPointerHash::const_iterator it = m_glyphPointerHash.constBegin(), - end = m_glyphPointerHash.constEnd(); it != end; ++it) { - for (QList<QFontEngineGlyphCache*>::const_iterator it2 = it.value().constBegin(), - end2 = it.value().constEnd(); it2 != end2; ++it2) { - delete *it2; - } - } - m_glyphPointerHash.clear(); - for (GlyphIntHash::const_iterator it = m_glyphIntHash.constBegin(), - end = m_glyphIntHash.constEnd(); it != end; ++it) { - for (QList<QFontEngineGlyphCache*>::const_iterator it2 = it.value().constBegin(), - end2 = it.value().constEnd(); it2 != end2; ++it2) { - delete *it2; - } + for (QLinkedList<GlyphCacheEntry>::const_iterator it = m_glyphCaches.constBegin(), + end = m_glyphCaches.constEnd(); it != end; ++it) { + delete it->cache; } - m_glyphIntHash.clear(); + m_glyphCaches.clear(); qHBFreeFace(hbFace); } @@ -713,103 +702,30 @@ QByteArray QFontEngine::getSfntTable(uint tag) const return table; } -void QFontEngine::expireGlyphCache() -{ - if (m_glyphCacheQueue.count() > 10) { // hold only 10 caches in memory. - QFontEngineGlyphCache *old = m_glyphCacheQueue.takeFirst(); - // remove the value from either of our hashes - for (GlyphPointerHash::iterator i = m_glyphPointerHash.begin(); i != m_glyphPointerHash.end(); ++i) { - QList<QFontEngineGlyphCache *> list = i.value(); - if (list.removeAll(old)) { - if (list.isEmpty()) - m_glyphPointerHash.remove(i.key()); - else - m_glyphPointerHash.insert(i.key(), list); - break; - } - } - for (GlyphIntHash::iterator i = m_glyphIntHash.begin(); i != m_glyphIntHash.end(); ++i) { - QList<QFontEngineGlyphCache *> list = i.value(); - if (list.removeAll(old)) { - if (list.isEmpty()) - m_glyphIntHash.remove(i.key()); - else - m_glyphIntHash.insert(i.key(), list); - break; - } - } - delete old; - } -} - void QFontEngine::setGlyphCache(void *key, QFontEngineGlyphCache *data) { Q_ASSERT(data); - QList<QFontEngineGlyphCache*> items = m_glyphPointerHash.value(key); - - for (QList<QFontEngineGlyphCache*>::iterator it = items.begin(), end = items.end(); it != end; ++it) { - QFontEngineGlyphCache *c = *it; - if (qtransform_equals_no_translate(c->m_transform, data->m_transform)) { - if (c == data) - return; - items.removeAll(c); - delete c; - break; - } - } - items.append(data); - m_glyphPointerHash.insert(key, items); - m_glyphCacheQueue.append(data); - expireGlyphCache(); -} + GlyphCacheEntry entry = { key, data }; + if (m_glyphCaches.contains(entry)) + return; -void QFontEngine::setGlyphCache(QFontEngineGlyphCache::Type key, QFontEngineGlyphCache *data) -{ - Q_ASSERT(data); - QList<QFontEngineGlyphCache*> items = m_glyphIntHash.value(key); - - for (QList<QFontEngineGlyphCache*>::iterator it = items.begin(), end = items.end(); it != end; ++it) { - QFontEngineGlyphCache *c = *it; - if (qtransform_equals_no_translate(c->m_transform, data->m_transform)) { - if (c == data) - return; - items.removeAll(c); - delete c; - break; - } - } - items.append(data); - m_glyphIntHash.insert(key, items); + // Limit the glyph caches to 4. This covers all 90 degree rotations and limits + // memory use when there is continous or random rotation + if (m_glyphCaches.size() == 4) + delete m_glyphCaches.takeLast().cache; - m_glyphCacheQueue.append(data); - expireGlyphCache(); -} + m_glyphCaches.push_front(entry); -QFontEngineGlyphCache *QFontEngine::glyphCache(void *key, const QTransform &transform) const -{ - QList<QFontEngineGlyphCache*> items = m_glyphPointerHash.value(key); - - for (QList<QFontEngineGlyphCache*>::iterator it = items.begin(), end = items.end(); it != end; ++it) { - QFontEngineGlyphCache *c = *it; - if (qtransform_equals_no_translate(c->m_transform, transform)) { - m_glyphCacheQueue.removeAll(c); // last used, move it up - m_glyphCacheQueue.append(c); - return c; - } - } - return 0; } -QFontEngineGlyphCache *QFontEngine::glyphCache(QFontEngineGlyphCache::Type key, const QTransform &transform) const +QFontEngineGlyphCache *QFontEngine::glyphCache(void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const { - QList<QFontEngineGlyphCache*> items = m_glyphIntHash.value(key); - - for (QList<QFontEngineGlyphCache*>::iterator it = items.begin(), end = items.end(); it != end; ++it) { - QFontEngineGlyphCache *c = *it; - if (qtransform_equals_no_translate(c->m_transform, transform)) { - m_glyphCacheQueue.removeAll(c); // last used, move it up - m_glyphCacheQueue.append(c); + for (QLinkedList<GlyphCacheEntry>::const_iterator it = m_glyphCaches.constBegin(), end = m_glyphCaches.constEnd(); it != end; ++it) { + QFontEngineGlyphCache *c = it->cache; + if (key == it->context + && type == c->cacheType() + && qtransform_equals_no_translate(c->m_transform, transform)) { return c; } } diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm index a4e7c04..a75d70f 100644 --- a/src/gui/text/qfontengine_mac.mm +++ b/src/gui/text/qfontengine_mac.mm @@ -404,7 +404,9 @@ QFixed QCoreTextFontEngine::ascent() const } QFixed QCoreTextFontEngine::descent() const { - return QFixed::fromReal(CTFontGetDescent(ctfont)).ceil(); + // subtract a pixel to even out the historical +1 in QFontMetrics::height(). + // Fix in Qt 5. + return QFixed::fromReal(CTFontGetDescent(ctfont)).ceil() - 1; } QFixed QCoreTextFontEngine::leading() const { @@ -1406,7 +1408,9 @@ QFixed QFontEngineMac::ascent() const QFixed QFontEngineMac::descent() const { - return m_descent; + // subtract a pixel to even out the historical +1 in QFontMetrics::height(). + // Fix in Qt 5. + return m_descent - 1; } QFixed QFontEngineMac::leading() const diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 728c344..a9883b4 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -56,6 +56,7 @@ #include "QtCore/qglobal.h" #include "QtCore/qatomic.h" #include <QtCore/qvarlengtharray.h> +#include <QtCore/QLinkedList> #include "private/qtextengine_p.h" #include "private/qfont_p.h" @@ -219,9 +220,7 @@ public: virtual HB_Error getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints); void setGlyphCache(void *key, QFontEngineGlyphCache *data); - void setGlyphCache(QFontEngineGlyphCache::Type key, QFontEngineGlyphCache *data); - QFontEngineGlyphCache *glyphCache(void *key, const QTransform &transform) const; - QFontEngineGlyphCache *glyphCache(QFontEngineGlyphCache::Type key, const QTransform &transform) const; + QFontEngineGlyphCache *glyphCache(void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const; static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize); static quint32 getTrueTypeGlyphIndex(const uchar *cmap, uint unicode); @@ -254,12 +253,13 @@ protected: static const QVector<QRgb> &grayPalette(); private: - /// remove old entries from the glyph cache. Helper method for the setGlyphCache ones. - void expireGlyphCache(); + struct GlyphCacheEntry { + void *context; + QFontEngineGlyphCache *cache; + bool operator==(const GlyphCacheEntry &other) { return context == other.context && cache == other.cache; } + }; - GlyphPointerHash m_glyphPointerHash; - GlyphIntHash m_glyphIntHash; - mutable QList<QFontEngineGlyphCache*> m_glyphCacheQueue; + mutable QLinkedList<GlyphCacheEntry> m_glyphCaches; }; inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId &f2) diff --git a/src/gui/text/qfontengineglyphcache_p.h b/src/gui/text/qfontengineglyphcache_p.h index e04f4ac..c6112ba 100644 --- a/src/gui/text/qfontengineglyphcache_p.h +++ b/src/gui/text/qfontengineglyphcache_p.h @@ -75,17 +75,20 @@ QT_BEGIN_NAMESPACE class QFontEngineGlyphCache { public: - QFontEngineGlyphCache(const QTransform &matrix) : m_transform(matrix) { } - enum Type { Raster_RGBMask, Raster_A8, Raster_Mono }; + QFontEngineGlyphCache(const QTransform &matrix, Type type) : m_transform(matrix), m_type(type) { } + virtual ~QFontEngineGlyphCache() { } + Type cacheType() const { return m_type; } + QTransform m_transform; + QFontEngineGlyphCache::Type m_type; }; typedef QHash<void *, QList<QFontEngineGlyphCache *> > GlyphPointerHash; typedef QHash<int, QList<QFontEngineGlyphCache *> > GlyphIntHash; diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index f96f66b..f523226 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -1938,7 +1938,11 @@ void QTextControlPrivate::focusEvent(QFocusEvent *e) emit q->updateRequest(q->selectionRect()); if (e->gotFocus()) { #ifdef QT_KEYPAD_NAVIGATION - if (!QApplication::keypadNavigationEnabled() || (hasEditFocus && e->reason() == Qt::PopupFocusReason)) { + if (!QApplication::keypadNavigationEnabled() || (hasEditFocus && (e->reason() == Qt::PopupFocusReason +#ifdef Q_OS_SYMBIAN + || e->reason() == Qt::ActiveWindowFocusReason +#endif + ))) { #endif cursorOn = (interactionFlags & Qt::TextSelectableByKeyboard); if (interactionFlags & Qt::TextEditable) { diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index ce62834..f1dbf23 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -862,27 +862,28 @@ QTextLayout *QTextCursorPrivate::blockLayout(QTextBlock &block) const{ \ingroup richtext-processing \ingroup shared - - Text cursors are objects that are used to access and modify the contents - and underlying structure of text documents via a programming interface - that mimics the behavior of a cursor in a text editor. QTextCursor contains - information about both the cursor's position within a QTextDocument and any - selection that it has made. + Text cursors are objects that are used to access and modify the + contents and underlying structure of text documents via a + programming interface that mimics the behavior of a cursor in a + text editor. QTextCursor contains information about both the + cursor's position within a QTextDocument and any selection that it + has made. QTextCursor is modeled on the way a text cursor behaves in a text - editor, providing a programmatic means of performing standard actions - through the user interface. A document can be thought of as a - single string of characters with the cursor's position() being \e - between any two characters (or at the very beginning or very end - of the document). Documents can also contain tables, lists, - images, and other objects in addition to text but, from the developer's - point of view, the document can be treated as one long string. - Some portions of that string can be considered to lie within particular - blocks (e.g. paragraphs), or within a table's cell, or a list's item, - or other structural elements. When we refer to "current character" we - mean the character immediately after the cursor position() in the - document; similarly the "current block" is the block that contains the - cursor position(). + editor, providing a programmatic means of performing standard + actions through the user interface. A document can be thought of + as a single string of characters. The cursor's current position() + then is always either \e between two consecutive characters in the + string, or else \e before the very first character or \e after the + very last character in the string. Documents can also contain + tables, lists, images, and other objects in addition to text but, + from the developer's point of view, the document can be treated as + one long string. Some portions of that string can be considered + to lie within particular blocks (e.g. paragraphs), or within a + table's cell, or a list's item, or other structural elements. When + we refer to "current character" we mean the character immediately + \e before the cursor position() in the document. Similarly, the + "current block" is the block that contains the cursor position(). A QTextCursor also has an anchor() position. The text that is between the anchor() and the position() is the selection. If @@ -940,11 +941,12 @@ QTextLayout *QTextCursorPrivate::blockLayout(QTextBlock &block) const{ undo/redo) using beginEditBlock() and endEditBlock(). Cursor movements are limited to valid cursor positions. In Latin - writing this is usually after every character in the text. In some - other writing systems cursor movements are limited to "clusters" - (e.g. a syllable in Devanagari, or a base letter plus diacritics). - Functions such as movePosition() and deleteChar() limit cursor - movement to these valid positions. + writing this is between any two consecutive characters in the + text, before the first character, or after the last character. In + some other writing systems cursor movements are limited to + "clusters" (e.g. a syllable in Devanagari, or a base letter plus + diacritics). Functions such as movePosition() and deleteChar() + limit cursor movement to these valid positions. \sa \link richtext.html Rich Text Processing\endlink @@ -1739,8 +1741,9 @@ void QTextCursor::mergeBlockCharFormat(const QTextCharFormat &modifier) } /*! - Returns the format of the character immediately before the cursor position(). If the cursor is - positioned at the beginning of a text block that is not empty then the format of the character + Returns the format of the character immediately before the cursor + position(). If the cursor is positioned at the beginning of a text + block that is not empty then the format of the character immediately after the cursor is returned. \sa insertText(), blockFormat() diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp index 1bd4dd6..dcc2e7d 100644 --- a/src/gui/text/qtextodfwriter.cpp +++ b/src/gui/text/qtextodfwriter.cpp @@ -484,6 +484,10 @@ void QTextOdfWriter::writeBlockFormat(QXmlStreamWriter &writer, QTextBlockFormat if (format.pageBreakPolicy() & QTextFormat::PageBreak_AlwaysAfter) writer.writeAttribute(foNS, QString::fromLatin1("break-after"), QString::fromLatin1("page")); } + if (format.hasProperty(QTextFormat::BackgroundBrush)) { + QBrush brush = format.background(); + writer.writeAttribute(foNS, QString::fromLatin1("background-color"), brush.color().name()); + } if (format.hasProperty(QTextFormat::BlockNonBreakableLines)) writer.writeAttribute(foNS, QString::fromLatin1("keep-together"), format.nonBreakableLines() ? QString::fromLatin1("true") : QString::fromLatin1("false")); @@ -552,8 +556,8 @@ void QTextOdfWriter::writeCharacterFormat(QXmlStreamWriter &writer, QTextCharFor } if (format.hasProperty(QTextFormat::FontLetterSpacing)) writer.writeAttribute(foNS, QString::fromLatin1("letter-spacing"), pixelToPoint(format.fontLetterSpacing())); - if (format.hasProperty(QTextFormat::FontWordSpacing)) - writer.writeAttribute(foNS, QString::fromLatin1("word-spacing"), pixelToPoint(format.fontWordSpacing())); + if (format.hasProperty(QTextFormat::FontWordSpacing) && format.fontWordSpacing() != 0) + writer.writeAttribute(foNS, QString::fromLatin1("word-spacing"), pixelToPoint(format.fontWordSpacing())); if (format.hasProperty(QTextFormat::FontUnderline)) writer.writeAttribute(styleNS, QString::fromLatin1("text-underline-type"), format.fontUnderline() ? QString::fromLatin1("single") : QString::fromLatin1("none")); @@ -610,9 +614,12 @@ void QTextOdfWriter::writeCharacterFormat(QXmlStreamWriter &writer, QTextCharFor } if (format.hasProperty(QTextFormat::ForegroundBrush)) { QBrush brush = format.foreground(); - // TODO writer.writeAttribute(foNS, QString::fromLatin1("color"), brush.color().name()); } + if (format.hasProperty(QTextFormat::BackgroundBrush)) { + QBrush brush = format.background(); + writer.writeAttribute(foNS, QString::fromLatin1("background-color"), brush.color().name()); + } writer.writeEndElement(); // style } diff --git a/src/gui/util/qsystemtrayicon_p.h b/src/gui/util/qsystemtrayicon_p.h index 86de366..029a259 100644 --- a/src/gui/util/qsystemtrayicon_p.h +++ b/src/gui/util/qsystemtrayicon_p.h @@ -94,6 +94,7 @@ public: class QBalloonTip : public QWidget { + Q_OBJECT public: static void showBalloon(QSystemTrayIcon::MessageIcon icon, const QString& title, const QString& msg, QSystemTrayIcon *trayIcon, diff --git a/src/gui/util/qsystemtrayicon_win.cpp b/src/gui/util/qsystemtrayicon_win.cpp index 362be5b..474555b 100644 --- a/src/gui/util/qsystemtrayicon_win.cpp +++ b/src/gui/util/qsystemtrayicon_win.cpp @@ -83,7 +83,11 @@ struct Q_NOTIFYICONIDENTIFIER { GUID guidItem; }; +#define Q_MSGFLT_ALLOW 1 + typedef HRESULT (WINAPI *PtrShell_NotifyIconGetRect)(const Q_NOTIFYICONIDENTIFIER* identifier, RECT* iconLocation); +typedef BOOL (WINAPI *PtrChangeWindowMessageFilter)(UINT message, DWORD dwFlag); +typedef BOOL (WINAPI *PtrChangeWindowMessageFilterEx)(HWND hWnd, UINT message, DWORD action, void* pChangeFilterStruct); class QSystemTrayIconSys : QWidget { @@ -143,6 +147,23 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *object) if (!MYWM_TASKBARCREATED) { MYWM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated"); } + + // Allow the WM_TASKBARCREATED message through the UIPI filter on Windows Vista and higher + static PtrChangeWindowMessageFilterEx pChangeWindowMessageFilterEx = + (PtrChangeWindowMessageFilterEx)QLibrary::resolve(QLatin1String("user32"), "ChangeWindowMessageFilterEx"); + + if (pChangeWindowMessageFilterEx) { + // Call the safer ChangeWindowMessageFilterEx API if available + pChangeWindowMessageFilterEx(winId(), MYWM_TASKBARCREATED, Q_MSGFLT_ALLOW, 0); + } else { + static PtrChangeWindowMessageFilter pChangeWindowMessageFilter = + (PtrChangeWindowMessageFilter)QLibrary::resolve(QLatin1String("user32"), "ChangeWindowMessageFilter"); + + if (pChangeWindowMessageFilter) { + // Call the deprecated ChangeWindowMessageFilter API otherwise + pChangeWindowMessageFilter(MYWM_TASKBARCREATED, Q_MSGFLT_ALLOW); + } + } } QSystemTrayIconSys::~QSystemTrayIconSys() diff --git a/src/gui/widgets/qabstractspinbox.cpp b/src/gui/widgets/qabstractspinbox.cpp index a18af4f..e26d5c3 100644 --- a/src/gui/widgets/qabstractspinbox.cpp +++ b/src/gui/widgets/qabstractspinbox.cpp @@ -65,6 +65,11 @@ #include <limits.h> #endif +#if defined(Q_OS_SYMBIAN) +#include <W32STD.H> +#include <private/qt_s60_p.h> +#endif + //#define QABSTRACTSPINBOX_QSBDEBUG #ifdef QABSTRACTSPINBOX_QSBDEBUG # define QASBDEBUG qDebug @@ -939,10 +944,12 @@ void QAbstractSpinBox::keyPressEvent(QKeyEvent *event) d->edit->setCursorPosition(d->prefix.size()); int steps = 1; + bool isPgUpOrDown = false; switch (event->key()) { case Qt::Key_PageUp: case Qt::Key_PageDown: steps *= 10; + isPgUpOrDown = true; case Qt::Key_Up: case Qt::Key_Down: { #ifdef QT_KEYPAD_NAVIGATION @@ -964,7 +971,13 @@ void QAbstractSpinBox::keyPressEvent(QKeyEvent *event) if (style()->styleHint(QStyle::SH_SpinBox_AnimateButton, 0, this)) { d->buttonState = (Keyboard | (up ? Up : Down)); } - stepBy(steps); + if (d->spinClickTimerId == -1) + stepBy(steps); + if(event->isAutoRepeat() && !isPgUpOrDown) { + if(d->spinClickThresholdTimerId == -1 && d->spinClickTimerId == -1) { + d->updateState(up, true); + } + } #ifndef QT_NO_ACCESSIBILITY QAccessible::updateAccessibility(this, 0, QAccessible::ValueChanged); #endif @@ -1061,8 +1074,7 @@ void QAbstractSpinBox::keyReleaseEvent(QKeyEvent *event) { Q_D(QAbstractSpinBox); - if (d->buttonState & Keyboard && !event->isAutoRepeat() - && style()->styleHint(QStyle::SH_SpinBox_AnimateButton, 0, this)) { + if (d->buttonState & Keyboard && !event->isAutoRepeat()) { d->reset(); } else { d->edit->event(event); @@ -1148,6 +1160,34 @@ void QAbstractSpinBox::hideEvent(QHideEvent *event) QWidget::hideEvent(event); } + +/*! + \internal + + Used when acceleration is turned on. We need to get the + keyboard auto repeat rate from OS. This value is used as + argument when starting acceleration related timers. + + Every platform should, either, use native calls to obtain + the value or hard code some reasonable rate. + + Remember that time value should be given in msecs. +*/ +static int getKeyboardAutoRepeatRate() { + int ret = 30; +#if defined(Q_OS_SYMBIAN) + TTimeIntervalMicroSeconds32 initialTime; + TTimeIntervalMicroSeconds32 time; + S60->wsSession().GetKeyboardRepeatRate(initialTime, time); + ret = time.Int() / 1000; // msecs +#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + DWORD time; + if (SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &time, 0) != FALSE) + ret = static_cast<int>(1000 / static_cast<int>(time)); // msecs +#endif + return ret; // msecs +} + /*! \reimp */ @@ -1160,14 +1200,17 @@ void QAbstractSpinBox::timerEvent(QTimerEvent *event) if (event->timerId() == d->spinClickThresholdTimerId) { killTimer(d->spinClickThresholdTimerId); d->spinClickThresholdTimerId = -1; - d->spinClickTimerId = startTimer(d->spinClickTimerInterval); + d->effectiveSpinRepeatRate = d->buttonState & Keyboard + ? getKeyboardAutoRepeatRate() + : d->spinClickTimerInterval; + d->spinClickTimerId = startTimer(d->effectiveSpinRepeatRate); doStep = true; } else if (event->timerId() == d->spinClickTimerId) { if (d->accelerate) { - d->acceleration = d->acceleration + (int)(d->spinClickTimerInterval * 0.05); - if (d->spinClickTimerInterval - d->acceleration >= 10) { + d->acceleration = d->acceleration + (int)(d->effectiveSpinRepeatRate * 0.05); + if (d->effectiveSpinRepeatRate - d->acceleration >= 10) { killTimer(d->spinClickTimerId); - d->spinClickTimerId = startTimer(d->spinClickTimerInterval - d->acceleration); + d->spinClickTimerId = startTimer(d->effectiveSpinRepeatRate - d->acceleration); } } doStep = true; @@ -1308,8 +1351,8 @@ void QAbstractSpinBox::mouseReleaseEvent(QMouseEvent *event) QAbstractSpinBoxPrivate::QAbstractSpinBoxPrivate() : edit(0), type(QVariant::Invalid), spinClickTimerId(-1), spinClickTimerInterval(100), spinClickThresholdTimerId(-1), spinClickThresholdTimerInterval(-1), - buttonState(None), cachedText(QLatin1String("\x01")), cachedState(QValidator::Invalid), - pendingEmit(false), readOnly(false), wrapping(false), + effectiveSpinRepeatRate(1), buttonState(None), cachedText(QLatin1String("\x01")), + cachedState(QValidator::Invalid), pendingEmit(false), readOnly(false), wrapping(false), ignoreCursorPositionChanged(false), frame(true), accelerate(false), keyboardTracking(true), cleared(false), ignoreUpdateEdit(false), correctionMode(QAbstractSpinBox::CorrectToPreviousValue), acceleration(0), hoverControl(QStyle::SC_None), buttonSymbols(QAbstractSpinBox::UpDownArrows), validator(0) @@ -1554,7 +1597,7 @@ void QAbstractSpinBoxPrivate::reset() Updates the state of the spinbox. */ -void QAbstractSpinBoxPrivate::updateState(bool up) +void QAbstractSpinBoxPrivate::updateState(bool up, bool fromKeyboard /* = false */) { Q_Q(QAbstractSpinBox); if ((up && (buttonState & Up)) || (!up && (buttonState & Down))) @@ -1563,7 +1606,7 @@ void QAbstractSpinBoxPrivate::updateState(bool up) if (q && (q->stepEnabled() & (up ? QAbstractSpinBox::StepUpEnabled : QAbstractSpinBox::StepDownEnabled))) { spinClickThresholdTimerId = q->startTimer(spinClickThresholdTimerInterval); - buttonState = (up ? (Mouse | Up) : (Mouse | Down)); + buttonState = (up ? Up : Down) | (fromKeyboard ? Keyboard : Mouse); q->stepBy(up ? 1 : -1); #ifndef QT_NO_ACCESSIBILITY QAccessible::updateAccessibility(q, 0, QAccessible::ValueChanged); @@ -1856,8 +1899,10 @@ QValidator::State QSpinBoxValidator::validate(QString &input, int &pos) const if (dptr->specialValueText.size() > 0 && input == dptr->specialValueText) return QValidator::Acceptable; - if (!dptr->prefix.isEmpty() && !input.startsWith(dptr->prefix)) + if (!dptr->prefix.isEmpty() && !input.startsWith(dptr->prefix)) { input.prepend(dptr->prefix); + pos += dptr->prefix.length(); + } if (!dptr->suffix.isEmpty() && !input.endsWith(dptr->suffix)) input.append(dptr->suffix); diff --git a/src/gui/widgets/qabstractspinbox_p.h b/src/gui/widgets/qabstractspinbox_p.h index 3020cbc..55f94d7 100644 --- a/src/gui/widgets/qabstractspinbox_p.h +++ b/src/gui/widgets/qabstractspinbox_p.h @@ -98,7 +98,7 @@ public: void init(); void reset(); - void updateState(bool up); + void updateState(bool up, bool fromKeyboard = false); QString stripped(const QString &text, int *pos = 0) const; bool specialValue() const; virtual QVariant getZeroVariant() const; @@ -129,6 +129,7 @@ public: QVariant value, minimum, maximum, singleStep; QVariant::Type type; int spinClickTimerId, spinClickTimerInterval, spinClickThresholdTimerId, spinClickThresholdTimerInterval; + int effectiveSpinRepeatRate; uint buttonState; mutable QString cachedText; mutable QVariant cachedValue; diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index bd1d8ba..b7dd20c 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -931,7 +931,10 @@ void QComboBoxPrivate::init() QSizePolicy::ComboBox)); setLayoutItemMargins(QStyle::SE_ComboBoxLayoutItem); q->setModel(new QStandardItemModel(0, 1, q)); - q->setAttribute(Qt::WA_InputMethodEnabled); + if (!q->isEditable()) + q->setAttribute(Qt::WA_InputMethodEnabled, false); + else + q->setAttribute(Qt::WA_InputMethodEnabled); } QComboBoxPrivateContainer* QComboBoxPrivate::viewContainer() diff --git a/src/gui/widgets/qdial.cpp b/src/gui/widgets/qdial.cpp index 95e6ed5..dc02c02 100644 --- a/src/gui/widgets/qdial.cpp +++ b/src/gui/widgets/qdial.cpp @@ -59,6 +59,7 @@ #ifndef QT_NO_ACCESSIBILITY #include "qaccessible.h" #endif +#include <qmath.h> QT_BEGIN_NAMESPACE @@ -135,7 +136,7 @@ int QDialPrivate::valueFromPoint(const QPoint &p) const Q_Q(const QDial); double yy = (double)q->height()/2.0 - p.y(); double xx = (double)p.x() - q->width()/2.0; - double a = (xx || yy) ? atan2(yy, xx) : 0; + double a = (xx || yy) ? qAtan2(yy, xx) : 0; if (a < Q_PI / -2) a = a + Q_PI * 2; diff --git a/src/gui/widgets/qdockarealayout.cpp b/src/gui/widgets/qdockarealayout.cpp index 0a26a77..cf82da0 100644 --- a/src/gui/widgets/qdockarealayout.cpp +++ b/src/gui/widgets/qdockarealayout.cpp @@ -1303,9 +1303,9 @@ QDockAreaLayoutInfo *QDockAreaLayoutInfo::info(const QList<int> &path) index = -index - 1; if (index >= item_list.count()) return this; - if (path.count() == 1 || item_list.at(index).subinfo == 0) + if (path.count() == 1 || item_list[index].subinfo == 0) return this; - return item_list.at(index).subinfo->info(path.mid(1)); + return item_list[index].subinfo->info(path.mid(1)); } QRect QDockAreaLayoutInfo::itemRect(int index) const diff --git a/src/gui/widgets/qlcdnumber.h b/src/gui/widgets/qlcdnumber.h index e65637d..b7162cd 100644 --- a/src/gui/widgets/qlcdnumber.h +++ b/src/gui/widgets/qlcdnumber.h @@ -82,9 +82,10 @@ public: }; bool smallDecimalPoint() const; - +#ifdef QT_DEPRECATED QT_DEPRECATED int numDigits() const; QT_DEPRECATED void setNumDigits(int nDigits); +#endif int digitCount() const; void setDigitCount(int nDigits); diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 2c1acdb..573b2b5 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -1445,6 +1445,16 @@ bool QLineEdit::event(QEvent * e) d->control->processEvent(e); } else if (e->type() == QEvent::KeyRelease) { d->control->setCursorBlinkPeriod(QApplication::cursorFlashTime()); + } else if (e->type() == QEvent::Show) { + //In order to get the cursor blinking if QComboBox::setEditable is called when the combobox has focus + if (hasFocus()) { + d->control->setCursorBlinkPeriod(QApplication::cursorFlashTime()); + QStyleOptionFrameV2 opt; + initStyleOption(&opt); + if ((!hasSelectedText() && d->control->preeditAreaText().isEmpty()) + || style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this)) + d->setCursorVisible(true); + } } #ifdef QT_KEYPAD_NAVIGATION @@ -1751,7 +1761,11 @@ void QLineEdit::focusInEvent(QFocusEvent *e) d->clickCausedFocus = 1; } #ifdef QT_KEYPAD_NAVIGATION - if (!QApplication::keypadNavigationEnabled() || (hasEditFocus() && e->reason() == Qt::PopupFocusReason)){ + if (!QApplication::keypadNavigationEnabled() || (hasEditFocus() && ( e->reason() == Qt::PopupFocusReason +#ifdef Q_OS_SYMBIAN + || e->reason() == Qt::ActiveWindowFocusReason +#endif + ))) { #endif d->control->setCursorBlinkPeriod(QApplication::cursorFlashTime()); QStyleOptionFrameV2 opt; diff --git a/src/gui/widgets/qlineedit.h b/src/gui/widgets/qlineedit.h index 594e488..3f159f6 100644 --- a/src/gui/widgets/qlineedit.h +++ b/src/gui/widgets/qlineedit.h @@ -288,6 +288,7 @@ private: #ifdef QT_KEYPAD_NAVIGATION Q_PRIVATE_SLOT(d_func(), void _q_editFocusChange(bool)) #endif + Q_PRIVATE_SLOT(d_func(), void _q_selectionChanged()) }; #endif // QT_NO_LINEEDIT diff --git a/src/gui/widgets/qlineedit_p.cpp b/src/gui/widgets/qlineedit_p.cpp index 4437fef..c18ca25 100644 --- a/src/gui/widgets/qlineedit_p.cpp +++ b/src/gui/widgets/qlineedit_p.cpp @@ -126,6 +126,21 @@ void QLineEditPrivate::_q_editFocusChange(bool e) } #endif +void QLineEditPrivate::_q_selectionChanged() +{ + Q_Q(QLineEdit); + if (control->preeditAreaText().isEmpty()) { + QStyleOptionFrameV2 opt; + q->initStyleOption(&opt); + bool showCursor = control->hasSelectedText() ? + q->style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, q): + true; + setCursorVisible(showCursor); + } + + emit q->selectionChanged(); +} + void QLineEditPrivate::init(const QString& txt) { Q_Q(QLineEdit); @@ -138,7 +153,7 @@ void QLineEditPrivate::init(const QString& txt) QObject::connect(control, SIGNAL(cursorPositionChanged(int,int)), q, SLOT(_q_cursorPositionChanged(int,int))); QObject::connect(control, SIGNAL(selectionChanged()), - q, SIGNAL(selectionChanged())); + q, SLOT(_q_selectionChanged())); QObject::connect(control, SIGNAL(accepted()), q, SIGNAL(returnPressed())); QObject::connect(control, SIGNAL(editingFinished()), @@ -149,6 +164,9 @@ void QLineEditPrivate::init(const QString& txt) #endif QObject::connect(control, SIGNAL(cursorPositionChanged(int,int)), q, SLOT(updateMicroFocus())); + + QObject::connect(control, SIGNAL(textChanged(const QString &)), + q, SLOT(updateMicroFocus())); // for now, going completely overboard with updates. QObject::connect(control, SIGNAL(selectionChanged()), diff --git a/src/gui/widgets/qlineedit_p.h b/src/gui/widgets/qlineedit_p.h index dc648e8..f13dce2 100644 --- a/src/gui/widgets/qlineedit_p.h +++ b/src/gui/widgets/qlineedit_p.h @@ -128,7 +128,7 @@ public: #ifdef QT_KEYPAD_NAVIGATION void _q_editFocusChange(bool); #endif - + void _q_selectionChanged(); #ifndef QT_NO_COMPLETER void _q_completionHighlighted(QString); #endif diff --git a/src/gui/widgets/qmainwindow.h b/src/gui/widgets/qmainwindow.h index 8ee0507..316bbb8 100644 --- a/src/gui/widgets/qmainwindow.h +++ b/src/gui/widgets/qmainwindow.h @@ -102,8 +102,10 @@ public: Qt::ToolButtonStyle toolButtonStyle() const; void setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle); +#ifndef QT_NO_DOCKWIDGET bool isAnimated() const; bool isDockNestingEnabled() const; +#endif #ifndef QT_NO_TABBAR bool documentMode() const; diff --git a/src/gui/widgets/qmainwindowlayout_mac.mm b/src/gui/widgets/qmainwindowlayout_mac.mm index 8d8ffa7..6d50678 100644 --- a/src/gui/widgets/qmainwindowlayout_mac.mm +++ b/src/gui/widgets/qmainwindowlayout_mac.mm @@ -463,9 +463,6 @@ void QMainWindowLayout::removeFromMacToolbar(QToolBar *toolbar) NSToolbarItem *item = static_cast<NSToolbarItem *>(it.key()); [[qt_mac_window_for(layoutState.mainWindow->window()) toolbar] removeItemAtIndex:toolbarItemsCopy.indexOf(item)]; - // In Carbon this hash and list gets emptied via events. In Cocoa, we have to do it ourselves here. - it = unifiedToolbarHash.erase(it); - qtoolbarsInUnifiedToolbarList.removeAll(toolbar); #endif break; } diff --git a/src/gui/widgets/qmdiarea.cpp b/src/gui/widgets/qmdiarea.cpp index f3dbe34..a4a4cb2 100644 --- a/src/gui/widgets/qmdiarea.cpp +++ b/src/gui/widgets/qmdiarea.cpp @@ -1853,11 +1853,11 @@ void QMdiArea::closeAllSubWindows() } /*! - Gives the keyboard focus to the next window in the list of child - windows. The windows are activated in the order in which they are - created (CreationOrder). + Gives the keyboard focus to another window in the list of child + windows. The window activated will be the next one determined + by the current \l{QMdiArea::WindowOrder} {activation order}. - \sa activatePreviousSubWindow() + \sa activatePreviousSubWindow(), QMdiArea::WindowOrder */ void QMdiArea::activateNextSubWindow() { @@ -1871,11 +1871,11 @@ void QMdiArea::activateNextSubWindow() } /*! - Gives the keyboard focus to the previous window in the list of - child windows. The windows are activated in the order in which - they are created (CreationOrder). + Gives the keyboard focus to another window in the list of child + windows. The window activated will be the previous one determined + by the current \l{QMdiArea::WindowOrder} {activation order}. - \sa activateNextSubWindow() + \sa activateNextSubWindow(), QMdiArea::WindowOrder */ void QMdiArea::activatePreviousSubWindow() { diff --git a/src/gui/widgets/qplaintextedit.cpp b/src/gui/widgets/qplaintextedit.cpp index 89fe7b8..a3624d6 100644 --- a/src/gui/widgets/qplaintextedit.cpp +++ b/src/gui/widgets/qplaintextedit.cpp @@ -684,8 +684,12 @@ void QPlainTextEditPrivate::ensureVisible(int position, bool center, bool forceC qreal h = center ? line.naturalTextRect().center().y() : line.naturalTextRect().bottom(); + QTextBlock previousVisibleBlock = block; while (h < height && block.previous().isValid()) { - block = block.previous(); + previousVisibleBlock = block; + do { + block = block.previous(); + } while (!block.isVisible() && block.previous().isValid()); h += q->blockBoundingRect(block).height(); } @@ -699,8 +703,8 @@ void QPlainTextEditPrivate::ensureVisible(int position, bool center, bool forceC ++l; } - if (block.next().isValid() && l >= lineCount) { - block = block.next(); + if (l >= lineCount) { + block = previousVisibleBlock; l = 0; } setTopBlock(block.blockNumber(), l); @@ -761,6 +765,7 @@ void QPlainTextEditPrivate::init(const QString &txt) QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(_q_cursorPositionChanged())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); + QObject::connect(control, SIGNAL(textChanged()), q, SLOT(updateMicroFocus())); // set a null page size initially to avoid any relayouting until the textedit // is shown. relayoutDocument() will take care of setting the page size to the diff --git a/src/gui/widgets/qprintpreviewwidget.h b/src/gui/widgets/qprintpreviewwidget.h index 08e596d..d8504de 100644 --- a/src/gui/widgets/qprintpreviewwidget.h +++ b/src/gui/widgets/qprintpreviewwidget.h @@ -82,7 +82,9 @@ public: ViewMode viewMode() const; ZoomMode zoomMode() const; int currentPage() const; +#ifdef QT_DEPRECATED QT_DEPRECATED int numPages() const; +#endif int pageCount() const; void setVisible(bool visible); diff --git a/src/gui/widgets/qtextedit.cpp b/src/gui/widgets/qtextedit.cpp index 1bc0bf1..5d8f134 100644 --- a/src/gui/widgets/qtextedit.cpp +++ b/src/gui/widgets/qtextedit.cpp @@ -158,6 +158,8 @@ void QTextEditPrivate::init(const QString &html) QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); + QObject::connect(control, SIGNAL(textChanged()), q, SLOT(updateMicroFocus())); + QTextDocument *doc = control->document(); // set a null page size initially to avoid any relayouting until the textedit // is shown. relayoutDocument() will take care of setting the page size to the diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp index 9ab4057..e6ca367 100644 --- a/src/network/access/qnetworkreply.cpp +++ b/src/network/access/qnetworkreply.cpp @@ -171,7 +171,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate() \value UnknownProxyError an unknown proxy-related error was detected - \value UnknownContentError an unknonwn error related to + \value UnknownContentError an unknown error related to the remote content was detected \value ProtocolFailure a breakdown in protocol was diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index c20812e..1667c10 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -273,7 +273,7 @@ void QNetworkReplyImplPrivate::handleNotifications() if (state != Working) return; - while (!current.isEmpty()) { + while (state == Working && !current.isEmpty()) { InternalNotifications notification = current.dequeue(); switch (notification) { case NotifyDownstreamReadyWrite: @@ -580,7 +580,7 @@ QNetworkReplyImpl::~QNetworkReplyImpl() void QNetworkReplyImpl::abort() { Q_D(QNetworkReplyImpl); - if (d->state == QNetworkReplyImplPrivate::Aborted) + if (d->state == QNetworkReplyImplPrivate::Finished || d->state == QNetworkReplyImplPrivate::Aborted) return; // stop both upload and download diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp index 98a39cd..e77a425 100644 --- a/src/network/kernel/qhostinfo.cpp +++ b/src/network/kernel/qhostinfo.cpp @@ -60,11 +60,9 @@ QT_BEGIN_NAMESPACE -Q_GLOBAL_STATIC(QHostInfoAgent, theAgent) -void QHostInfoAgent::staticCleanup() -{ - theAgent()->cleanup(); -} +#ifndef QT_NO_THREAD +Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager) +#endif //#define QHOSTINFO_DEBUG @@ -143,6 +141,9 @@ static QBasicAtomicInt theIdCounter = Q_BASIC_ATOMIC_INITIALIZER(1); \snippet doc/src/snippets/code/src_network_kernel_qhostinfo.cpp 4 + \note There is no guarantee on the order the signals will be emitted + if you start multiple requests with lookupHost(). + \sa abortHostLookup(), addresses(), error(), fromName() */ int QHostInfo::lookupHost(const QString &name, QObject *receiver, @@ -159,38 +160,32 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver, qRegisterMetaType<QHostInfo>("QHostInfo"); -#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) - QWindowsSockInit bust; // makes sure WSAStartup was callled -#endif - - QScopedPointer<QHostInfoResult> result(new QHostInfoResult); - result.data()->autoDelete = false; - QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)), - receiver, member); - int id = result.data()->lookupId = theIdCounter.fetchAndAddRelaxed(1); + int id = theIdCounter.fetchAndAddRelaxed(1); // generate unique ID if (name.isEmpty()) { - QHostInfo info(id); - info.setError(QHostInfo::HostNotFound); - info.setErrorString(QObject::tr("No host name given")); - QMetaObject::invokeMethod(result.data(), "emitResultsReady", Qt::QueuedConnection, - Q_ARG(QHostInfo, info)); - result.take()->autoDelete = true; + QHostInfo hostInfo(id); + hostInfo.setError(QHostInfo::HostNotFound); + hostInfo.setErrorString(QObject::tr("No host name given")); + QScopedPointer<QHostInfoResult> result(new QHostInfoResult); + QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)), + receiver, member, Qt::QueuedConnection); + result.data()->emitResultsReady(hostInfo); return id; } - QHostInfoAgent *agent = theAgent(); - agent->addHostName(name, result.take()); - -#if !defined QT_NO_THREAD - if (!agent->isRunning()) - agent->start(); +#ifdef QT_NO_THREAD + QHostInfo hostInfo = QHostInfoAgent::fromName(name); + hostInfo.setLookupId(id); + QScopedPointer<QHostInfoResult> result(new QHostInfoResult); + QObject::connect(result.data(), SIGNAL(resultsReady(QHostInfo)), + receiver, member, Qt::QueuedConnection); + result.data()->emitResultsReady(hostInfo); #else -// if (!agent->isRunning()) - agent->run(); -// else -// agent->wakeOne(); + QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id); + QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection); + theHostInfoLookupManager()->scheduleLookup(runnable); #endif + return id; } @@ -201,8 +196,12 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver, */ void QHostInfo::abortHostLookup(int id) { - QHostInfoAgent *agent = theAgent(); - agent->abortLookup(id); +#ifndef QT_NO_THREAD + theHostInfoLookupManager()->abortLookup(id); +#else + // we cannot abort if it was non threaded.. the result signal has already been posted + Q_UNUSED(id); +#endif } /*! @@ -228,70 +227,6 @@ QHostInfo QHostInfo::fromName(const QString &name) } /*! - \internal - Pops a query off the queries list, performs a blocking call to - QHostInfoAgent::lookupHost(), and emits the resultsReady() - signal. This process repeats until the queries list is empty. -*/ -void QHostInfoAgent::run() -{ -#ifndef QT_NO_THREAD - // Dont' allow thread termination during event delivery, but allow it - // during the actual blocking host lookup stage. - setTerminationEnabled(false); - forever -#endif - { - QHostInfoQuery *query; - { -#ifndef QT_NO_THREAD - // the queries list is shared between threads. lock all - // access to it. - QMutexLocker locker(&mutex); - if (!quit && queries.isEmpty()) - cond.wait(&mutex); - if (quit) { - // Reset the quit variable in case QCoreApplication is - // destroyed and recreated. - quit = false; - break; - } - if (queries.isEmpty()) - continue; -#else - if (queries.isEmpty()) - return; -#endif - query = queries.takeFirst(); - pendingQueryId = query->object->lookupId; - } - -#if defined(QHOSTINFO_DEBUG) - qDebug("QHostInfoAgent::run(%p): looking up \"%s\"", this, - query->hostName.toLatin1().constData()); -#endif - -#ifndef QT_NO_THREAD - // Start query - allow termination at this point, but not outside. We - // don't want to all termination during event delivery, but we don't - // want the lookup to prevent the app from quitting (the agent - // destructor terminates the thread). - setTerminationEnabled(true); -#endif - QHostInfo info = fromName(query->hostName); -#ifndef QT_NO_THREAD - setTerminationEnabled(false); -#endif - - int id = query->object->lookupId; - info.setLookupId(id); - if (pendingQueryId == id) - query->object->emitResultsReady(info); - delete query; - } -} - -/*! \enum QHostInfo::HostInfoError This enum describes the various errors that can occur when trying @@ -467,4 +402,174 @@ void QHostInfo::setErrorString(const QString &str) \sa hostName() */ +#ifndef QT_NO_THREAD +QHostInfoRunnable::QHostInfoRunnable(QString hn, int i) : toBeLookedUp(hn), id(i) +{ + setAutoDelete(true); +} + +// the QHostInfoLookupManager will at some point call this via a QThreadPool +void QHostInfoRunnable::run() +{ + QHostInfoLookupManager *manager = theHostInfoLookupManager(); + // check aborted + if (manager->wasAborted(id)) { + manager->lookupFinished(this); + return; + } + + // check cache + // FIXME + + // if not in cache: OS lookup + QHostInfo hostInfo = QHostInfoAgent::fromName(toBeLookedUp); + + // save to cache + // FIXME + + // check aborted again + if (manager->wasAborted(id)) { + manager->lookupFinished(this); + return; + } + + // signal emission + hostInfo.setLookupId(id); + resultEmitter.emitResultsReady(hostInfo); + + manager->lookupFinished(this); + + // thread goes back to QThreadPool +} + +QHostInfoLookupManager::QHostInfoLookupManager() : mutex(QMutex::Recursive), wasDeleted(false) +{ + moveToThread(QCoreApplicationPrivate::mainThread()); + threadPool.setMaxThreadCount(5); // do 5 DNS lookups in parallel +} + +QHostInfoLookupManager::~QHostInfoLookupManager() +{ + wasDeleted = true; +} + +void QHostInfoLookupManager::work() +{ + if (wasDeleted) + return; + + // goals of this function: + // - launch new lookups via the thread pool + // - make sure only one lookup per host/IP is in progress + + QMutexLocker locker(&mutex); + + if (!finishedLookups.isEmpty()) { + // remove ID from aborted if it is in there + for (int i = 0; i < finishedLookups.length(); i++) { + abortedLookups.removeAll(finishedLookups.at(i)->id); + } + + finishedLookups.clear(); + } + + if (!postponedLookups.isEmpty()) { + // try to start the postponed ones + + QMutableListIterator<QHostInfoRunnable*> iterator(postponedLookups); + while (iterator.hasNext()) { + QHostInfoRunnable* postponed = iterator.next(); + + // check if none of the postponed hostnames is currently running + bool alreadyRunning = false; + for (int i = 0; i < currentLookups.length(); i++) { + if (currentLookups.at(i)->toBeLookedUp == postponed->toBeLookedUp) { + alreadyRunning = true; + break; + } + } + if (!alreadyRunning) { + iterator.remove(); + scheduledLookups.prepend(postponed); // prepend! we want to finish it ASAP + } + } + } + + if (!scheduledLookups.isEmpty()) { + // try to start the new ones + QMutableListIterator<QHostInfoRunnable*> iterator(scheduledLookups); + while (iterator.hasNext()) { + QHostInfoRunnable *scheduled = iterator.next(); + + // check if a lookup for this host is already running, then postpone + for (int i = 0; i < currentLookups.size(); i++) { + if (currentLookups.at(i)->toBeLookedUp == scheduled->toBeLookedUp) { + iterator.remove(); + postponedLookups.append(scheduled); + scheduled = 0; + break; + } + } + + if (scheduled && threadPool.tryStart(scheduled)) { + // runnable now running in new thread, track this in currentLookups + iterator.remove(); + currentLookups.append(scheduled); + } else if (scheduled) { + // wanted to start, but could not because thread pool is busy + break; + } else { + // was postponed, continue iterating + continue; + } + }; + } +} + +// called by QHostInfo +void QHostInfoLookupManager::scheduleLookup(QHostInfoRunnable *r) +{ + if (wasDeleted) + return; + + QMutexLocker locker(&this->mutex); + scheduledLookups.enqueue(r); + work(); +} + +// called by QHostInfo +void QHostInfoLookupManager::abortLookup(int id) +{ + if (wasDeleted) + return; + + QMutexLocker locker(&this->mutex); + if (!abortedLookups.contains(id)) + abortedLookups.append(id); +} + +// called from QHostInfoRunnable +bool QHostInfoLookupManager::wasAborted(int id) +{ + if (wasDeleted) + return true; + + QMutexLocker locker(&this->mutex); + return abortedLookups.contains(id); +} + +// called from QHostInfoRunnable +void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r) +{ + if (wasDeleted) + return; + + QMutexLocker locker(&this->mutex); + currentLookups.removeOne(r); + finishedLookups.append(r); + work(); +} + +#endif // QT_NO_THREAD + QT_END_NAMESPACE diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index afd3570..643bb73 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -61,17 +61,17 @@ #include "QtCore/qobject.h" #include "QtCore/qpointer.h" -#if !defined QT_NO_THREAD +#ifndef QT_NO_THREAD #include "QtCore/qthread.h" -# define QHostInfoAgentBase QThread -#else -# define QHostInfoAgentBase QObject +#include "QtCore/qthreadpool.h" +#include "QtCore/qmutex.h" +#include "QtCore/qrunnable.h" +#include "QtCore/qlist.h" +#include "QtCore/qqueue.h" #endif QT_BEGIN_NAMESPACE -static const int QHOSTINFO_THREAD_WAIT = 250; // ms - class QHostInfoResult : public QObject { Q_OBJECT @@ -79,102 +79,18 @@ public Q_SLOTS: inline void emitResultsReady(const QHostInfo &info) { emit resultsReady(info); - if (autoDelete) - delete this; } Q_SIGNALS: - void resultsReady(const QHostInfo &info); - -public: - int lookupId; - bool autoDelete; + void resultsReady(const QHostInfo info); }; -struct QHostInfoQuery -{ - inline QHostInfoQuery() : object(0) {} - inline ~QHostInfoQuery() { delete object; } - inline QHostInfoQuery(const QString &name, QHostInfoResult *result) - : hostName(name), object(result) {} - - QString hostName; - QHostInfoResult *object; -}; - -class QHostInfoAgent : public QHostInfoAgentBase +// needs to be QObject because fromName calls tr() +class QHostInfoAgent : public QObject { Q_OBJECT public: - inline QHostInfoAgent() - { - // There is a chance that there will be two instances of - // QHostInfoAgent if two threads try to get Q_GLOBAL_STATIC - // object at the same time. The second object will be deleted - // immediately before anyone uses it, but we need to be - // careful about what we do in the constructor. - static QBasicAtomicInt done = Q_BASIC_ATOMIC_INITIALIZER(0); - if (done.testAndSetRelaxed(0, 1)) - qAddPostRoutine(staticCleanup); - moveToThread(QCoreApplicationPrivate::mainThread()); - quit = false; - pendingQueryId = -1; - } - inline ~QHostInfoAgent() - { cleanup(); } - - void run(); static QHostInfo fromName(const QString &hostName); - - inline void addHostName(const QString &name, QHostInfoResult *result) - { - QMutexLocker locker(&mutex); - queries << new QHostInfoQuery(name, result); - cond.wakeOne(); - } - - inline void abortLookup(int id) - { - QMutexLocker locker(&mutex); - for (int i = 0; i < queries.size(); ++i) { - QHostInfoResult *result = queries.at(i)->object; - if (result->lookupId == id) { - result->disconnect(); - delete queries.takeAt(i); - return; - } - } - if (pendingQueryId == id) - pendingQueryId = -1; - } - - static void staticCleanup(); - -public Q_SLOTS: - inline void cleanup() - { - { - QMutexLocker locker(&mutex); - qDeleteAll(queries); - queries.clear(); - quit = true; - cond.wakeOne(); - } -#ifndef QT_NO_THREAD - if (!wait(QHOSTINFO_THREAD_WAIT)) { - terminate(); - // Don't wait forever; see QTBUG-5296. - wait(QHOSTINFO_THREAD_WAIT); - } -#endif - } - -private: - QList<QHostInfoQuery *> queries; - QMutex mutex; - QWaitCondition cond; - volatile bool quit; - int pendingQueryId; }; class QHostInfoPrivate @@ -194,6 +110,52 @@ public: int lookupId; }; +#ifndef QT_NO_THREAD +// the following classes are used for the (normal) case: We use multiple threads to lookup DNS + +class QHostInfoRunnable : public QRunnable +{ +public: + QHostInfoRunnable (QString hn, int i); + void run(); + + QString toBeLookedUp; + int id; + QHostInfoResult resultEmitter; +}; + +class QHostInfoLookupManager : public QObject +{ + Q_OBJECT +public: + QHostInfoLookupManager(); + ~QHostInfoLookupManager(); + + void work(); + + // called from QHostInfo + void scheduleLookup(QHostInfoRunnable *r); + void abortLookup(int id); + + // called from QHostInfoRunnable + void lookupFinished(QHostInfoRunnable *r); + bool wasAborted(int id); + +protected: + QList<QHostInfoRunnable*> currentLookups; // in progress + QList<QHostInfoRunnable*> postponedLookups; // postponed because in progress for same host + QQueue<QHostInfoRunnable*> scheduledLookups; // not yet started + QList<QHostInfoRunnable*> finishedLookups; // recently finished + QList<int> abortedLookups; // ids of aborted lookups + + QThreadPool threadPool; + + QMutex mutex; + + bool wasDeleted; +}; +#endif + QT_END_NAMESPACE #endif // QHOSTINFO_P_H diff --git a/src/network/kernel/qhostinfo_win.cpp b/src/network/kernel/qhostinfo_win.cpp index 720aaa5..727a8b0 100644 --- a/src/network/kernel/qhostinfo_win.cpp +++ b/src/network/kernel/qhostinfo_win.cpp @@ -105,11 +105,7 @@ static void resolveLibrary() #include <qmutex.h> QMutex qPrivCEMutex; #endif -/* - Performs a blocking call to gethostbyname or getaddrinfo, stores - the results in a QHostInfo structure and emits the - resultsReady() signal. -*/ + QHostInfo QHostInfoAgent::fromName(const QString &hostName) { #if defined(Q_OS_WINCE) diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 8b4f364..fda47bd 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -520,13 +520,13 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc Q_Q(QAbstractSocket); #if defined (QABSTRACTSOCKET_DEBUG) QString typeStr; - if (q->socketType() == QAbstractSocket::TcpSocket) typeStr = "TcpSocket"; - else if (q->socketType() == QAbstractSocket::UdpSocket) typeStr = "UdpSocket"; - else typeStr = "UnknownSocketType"; + if (q->socketType() == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket"); + else if (q->socketType() == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket"); + else typeStr = QLatin1String("UnknownSocketType"); QString protocolStr; - if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = "IPv4Protocol"; - else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = "IPv6Protocol"; - else protocolStr = "UnknownNetworkLayerProtocol"; + if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol"); + else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol"); + else protocolStr = QLatin1String("UnknownNetworkLayerProtocol"); #endif resetSocketLayer(); @@ -873,15 +873,19 @@ void QAbstractSocketPrivate::_q_startConnecting(const QHostInfo &hostInfo) if (state != QAbstractSocket::HostLookupState) return; + if (hostLookupId != -1 && hostLookupId != hostInfo.lookupId()) { + qWarning("QAbstractSocketPrivate::_q_startConnecting() received hostInfo for wrong lookup ID %d expected %d", hostInfo.lookupId(), hostLookupId); + } + addresses = hostInfo.addresses(); #if defined(QABSTRACTSOCKET_DEBUG) - QString s = "{"; + QString s = QLatin1String("{"); for (int i = 0; i < addresses.count(); ++i) { - if (i != 0) s += ", "; + if (i != 0) s += QLatin1String(", "); s += addresses.at(i).toString(); } - s += '}'; + s += QLatin1Char('}'); qDebug("QAbstractSocketPrivate::_q_startConnecting(hostInfo == %s)", s.toLatin1().constData()); #endif diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index 5c28318..635a0c6 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -212,28 +212,14 @@ qint64 QHttpSocketEngine::bytesAvailable() const qint64 QHttpSocketEngine::read(char *data, qint64 maxlen) { Q_D(QHttpSocketEngine); - qint64 bytesRead = 0; - - if (!d->readBuffer.isEmpty()) { - // Read as much from the buffer as we can. - bytesRead = qMin((qint64)d->readBuffer.size(), maxlen); - memcpy(data, d->readBuffer.constData(), bytesRead); - data += bytesRead; - maxlen -= bytesRead; - d->readBuffer = d->readBuffer.mid(bytesRead); - } - - qint64 bytesReadFromSocket = d->socket->read(data, maxlen); + qint64 bytesRead = d->socket->read(data, maxlen); if (d->socket->state() == QAbstractSocket::UnconnectedState && d->socket->bytesAvailable() == 0) { emitReadNotification(); } - if (bytesReadFromSocket > 0) { - // Add to what we read so far. - bytesRead += bytesReadFromSocket; - } else if (bytesRead == 0 && bytesReadFromSocket == -1) { + if (bytesRead == -1) { // If nothing has been read so far, and the direct socket read // failed, return the socket's error. Otherwise, fall through and // return as much as we read so far. @@ -560,7 +546,7 @@ void QHttpSocketEngine::slotSocketReadNotification() } QHttpResponseHeader responseHeader(QString::fromLatin1(d->readBuffer)); - d->readBuffer.clear(); + d->readBuffer.clear(); // we parsed the proxy protocol response. from now on direct socket reading will be done int statusCode = responseHeader.statusCode(); if (statusCode == 200) { diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h index 76430db..1432bfb 100644 --- a/src/network/socket/qhttpsocketengine_p.h +++ b/src/network/socket/qhttpsocketengine_p.h @@ -162,7 +162,7 @@ public: QNetworkProxy proxy; QString peerName; QTcpSocket *socket; - QByteArray readBuffer; + QByteArray readBuffer; // only used for parsing the proxy response QHttpSocketEngine::HttpState state; QAuthenticator authenticator; bool readNotificationEnabled; diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h index e319389..e0033be 100644 --- a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h +++ b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h @@ -68,7 +68,7 @@ class Q_OPENGL_EXPORT QGLCustomShaderStage public: QGLCustomShaderStage(); virtual ~QGLCustomShaderStage(); - virtual void setUniforms(QGLShaderProgram*) = 0; + virtual void setUniforms(QGLShaderProgram*) {} void setUniformsDirty(); diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 8a8f483..326ea1f 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -170,13 +170,15 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) source.append(qShaderSnippets[MainVertexShader]); source.append(qShaderSnippets[PositionOnlyVertexShader]); vertexShader = new QGLShader(QGLShader::Vertex, context, this); - vertexShader->compileSourceCode(source); + if (!vertexShader->compileSourceCode(source)) + qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile"); source.clear(); source.append(qShaderSnippets[MainFragmentShader]); source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]); fragShader = new QGLShader(QGLShader::Fragment, context, this); - fragShader->compileSourceCode(source); + if (!fragShader->compileSourceCode(source)) + qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile"); simpleShaderProg = new QGLShaderProgram(context, this); simpleShaderProg->addShader(vertexShader); @@ -193,13 +195,15 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) source.append(qShaderSnippets[MainWithTexCoordsVertexShader]); source.append(qShaderSnippets[UntransformedPositionVertexShader]); vertexShader = new QGLShader(QGLShader::Vertex, context, this); - vertexShader->compileSourceCode(source); + if (!vertexShader->compileSourceCode(source)) + qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile"); source.clear(); source.append(qShaderSnippets[MainFragmentShader]); source.append(qShaderSnippets[ImageSrcFragmentShader]); fragShader = new QGLShader(QGLShader::Fragment, context, this); - fragShader->compileSourceCode(source); + if (!fragShader->compileSourceCode(source)) + qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile"); blitShaderProg = new QGLShaderProgram(context, this); blitShaderProg->addShader(vertexShader); @@ -214,6 +218,23 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) } +QGLEngineSharedShaders::~QGLEngineSharedShaders() +{ + QList<QGLEngineShaderProg*>::iterator itr; + for (itr = cachedPrograms.begin(); itr != cachedPrograms.end(); ++itr) + delete *itr; + + if (blitShaderProg) { + delete blitShaderProg; + blitShaderProg = 0; + } + + if (simpleShaderProg) { + delete simpleShaderProg; + simpleShaderProg = 0; + } +} + #if defined (QT_DEBUG) QByteArray QGLEngineSharedShaders::snippetNameStr(SnippetName name) { @@ -234,84 +255,95 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS } } - QByteArray source; - source.append(qShaderSnippets[prog.mainFragShader]); - source.append(qShaderSnippets[prog.srcPixelFragShader]); - if (prog.srcPixelFragShader == CustomImageSrcFragmentShader) - source.append(prog.customStageSource); - if (prog.compositionFragShader) - source.append(qShaderSnippets[prog.compositionFragShader]); - if (prog.maskFragShader) - source.append(qShaderSnippets[prog.maskFragShader]); - QGLShader* fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this); - fragShader->compileSourceCode(source); - - source.clear(); - source.append(qShaderSnippets[prog.mainVertexShader]); - source.append(qShaderSnippets[prog.positionVertexShader]); - QGLShader* vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this); - vertexShader->compileSourceCode(source); + QGLShader *vertexShader = 0; + QGLShader *fragShader = 0; + QGLEngineShaderProg *newProg = 0; + bool success = false; + + do { + QByteArray source; + source.append(qShaderSnippets[prog.mainFragShader]); + source.append(qShaderSnippets[prog.srcPixelFragShader]); + if (prog.srcPixelFragShader == CustomImageSrcFragmentShader) + source.append(prog.customStageSource); + if (prog.compositionFragShader) + source.append(qShaderSnippets[prog.compositionFragShader]); + if (prog.maskFragShader) + source.append(qShaderSnippets[prog.maskFragShader]); + fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this); + QByteArray description; +#if defined(QT_DEBUG) + // Name the shader for easier debugging + description.append("Fragment shader: main="); + description.append(snippetNameStr(prog.mainFragShader)); + description.append(", srcPixel="); + description.append(snippetNameStr(prog.srcPixelFragShader)); + if (prog.compositionFragShader) { + description.append(", composition="); + description.append(snippetNameStr(prog.compositionFragShader)); + } + if (prog.maskFragShader) { + description.append(", mask="); + description.append(snippetNameStr(prog.maskFragShader)); + } + fragShader->setObjectName(QString::fromLatin1(description)); +#endif + if (!fragShader->compileSourceCode(source)) { + qWarning() << "Warning:" << description << "failed to compile!"; + break; + } + source.clear(); + source.append(qShaderSnippets[prog.mainVertexShader]); + source.append(qShaderSnippets[prog.positionVertexShader]); + vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this); #if defined(QT_DEBUG) - // Name the shaders for easier debugging - QByteArray description; - description.append("Fragment shader: main="); - description.append(snippetNameStr(prog.mainFragShader)); - description.append(", srcPixel="); - description.append(snippetNameStr(prog.srcPixelFragShader)); - if (prog.compositionFragShader) { - description.append(", composition="); - description.append(snippetNameStr(prog.compositionFragShader)); - } - if (prog.maskFragShader) { - description.append(", mask="); - description.append(snippetNameStr(prog.maskFragShader)); - } - fragShader->setObjectName(QString::fromLatin1(description)); - - description.clear(); - description.append("Vertex shader: main="); - description.append(snippetNameStr(prog.mainVertexShader)); - description.append(", position="); - description.append(snippetNameStr(prog.positionVertexShader)); - vertexShader->setObjectName(QString::fromLatin1(description)); + // Name the shader for easier debugging + description.clear(); + description.append("Vertex shader: main="); + description.append(snippetNameStr(prog.mainVertexShader)); + description.append(", position="); + description.append(snippetNameStr(prog.positionVertexShader)); + vertexShader->setObjectName(QString::fromLatin1(description)); #endif + if (!vertexShader->compileSourceCode(source)) { + qWarning() << "Warning:" << description << "failed to compile!"; + break; + } - QGLEngineShaderProg* newProg = new QGLEngineShaderProg(prog); - - // If the shader program's not found in the cache, create it now. - newProg->program = new QGLShaderProgram(ctxGuard.context(), this); - newProg->program->addShader(vertexShader); - newProg->program->addShader(fragShader); - - // We have to bind the vertex attribute names before the program is linked: - newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); - if (newProg->useTextureCoords) - newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); - if (newProg->useOpacityAttribute) - newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR); - - newProg->program->link(); - if (!newProg->program->isLinked()) { - QLatin1String none("none"); - QLatin1String br("\n"); - QString error; - error = QLatin1String("Shader program failed to link,") + newProg = new QGLEngineShaderProg(prog); + + // If the shader program's not found in the cache, create it now. + newProg->program = new QGLShaderProgram(ctxGuard.context(), this); + newProg->program->addShader(vertexShader); + newProg->program->addShader(fragShader); + + // We have to bind the vertex attribute names before the program is linked: + newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + if (newProg->useTextureCoords) + newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); + if (newProg->useOpacityAttribute) + newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR); + + newProg->program->link(); + if (!newProg->program->isLinked()) { + QLatin1String none("none"); + QLatin1String br("\n"); + QString error; + error = QLatin1String("Shader program failed to link,") #if defined(QT_DEBUG) - + br - + QLatin1String(" Shaders Used:") + br - + QLatin1String(" ") + vertexShader->objectName() + QLatin1String(": ") + br - + QLatin1String(vertexShader->sourceCode()) + br - + QLatin1String(" ") + fragShader->objectName() + QLatin1String(": ") + br - + QLatin1String(fragShader->sourceCode()) + br + + br + + QLatin1String(" Shaders Used:") + br + + QLatin1String(" ") + vertexShader->objectName() + QLatin1String(": ") + br + + QLatin1String(vertexShader->sourceCode()) + br + + QLatin1String(" ") + fragShader->objectName() + QLatin1String(": ") + br + + QLatin1String(fragShader->sourceCode()) + br #endif - + QLatin1String(" Error Log:\n") - + QLatin1String(" ") + newProg->program->log(); - qWarning() << error; - delete newProg; // Deletes the QGLShaderProgram in it's destructor - newProg = 0; - } - else { + + QLatin1String(" Error Log:\n") + + QLatin1String(" ") + newProg->program->log(); + qWarning() << error; + break; + } if (cachedPrograms.count() > 30) { // The cache is full, so delete the last 5 programs in the list. // These programs will be least used, as a program us bumped to @@ -323,6 +355,22 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS } cachedPrograms.insert(0, newProg); + + success = true; + } while (false); + + // Clean up everything if we weren't successful + if (!success) { + if (newProg) { + delete newProg; // Also deletes the QGLShaderProgram which in turn deletes the QGLShaders + newProg = 0; + } + else { + if (vertexShader) + delete vertexShader; + if (fragShader) + delete fragShader; + } } return newProg; @@ -362,8 +410,11 @@ QGLEngineShaderManager::~QGLEngineShaderManager() removeCustomStage(); } -uint QGLEngineShaderManager::getUniformLocation(Uniform id) +GLuint QGLEngineShaderManager::getUniformLocation(Uniform id) { + if (!currentShaderProg) + return 0; + QVector<uint> &uniformLocations = currentShaderProg->uniformLocations; if (uniformLocations.isEmpty()) uniformLocations.fill(GLuint(-1), NumUniforms); @@ -394,9 +445,9 @@ uint QGLEngineShaderManager::getUniformLocation(Uniform id) } -void QGLEngineShaderManager::optimiseForBrushTransform(const QTransform &transform) +void QGLEngineShaderManager::optimiseForBrushTransform(QTransform::TransformationType transformType) { - Q_UNUSED(transform); // Currently ignored + Q_UNUSED(transformType); // Currently ignored } void QGLEngineShaderManager::setDirty() @@ -406,6 +457,7 @@ void QGLEngineShaderManager::setDirty() void QGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style) { + Q_ASSERT(style != Qt::NoBrush); if (srcPixelType == PixelSrcType(style)) return; @@ -467,7 +519,30 @@ void QGLEngineShaderManager::removeCustomStage() QGLShaderProgram* QGLEngineShaderManager::currentProgram() { - return currentShaderProg->program; + if (currentShaderProg) + return currentShaderProg->program; + else + return sharedShaders->simpleProgram(); +} + +void QGLEngineShaderManager::useSimpleProgram() +{ + sharedShaders->simpleProgram()->bind(); + QGLContextPrivate* ctx_d = ctx->d_func(); + ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true); + ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false); + ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); + shaderProgNeedsChanging = true; +} + +void QGLEngineShaderManager::useBlitProgram() +{ + sharedShaders->blitProgram()->bind(); + QGLContextPrivate* ctx_d = ctx->d_func(); + ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true); + ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, true); + ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); + shaderProgNeedsChanging = true; } QGLShaderProgram* QGLEngineShaderManager::simpleProgram() @@ -678,6 +753,13 @@ bool QGLEngineShaderManager::useCorrectShaderProg() customSrcStage->setUniforms(currentShaderProg->program); } + // Make sure all the vertex attribute arrays the program uses are enabled (and the ones it + // doesn't use are disabled) + QGLContextPrivate* ctx_d = ctx->d_func(); + ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true); + ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, currentShaderProg->useTextureCoords); + ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, currentShaderProg->useOpacityAttribute); + shaderProgNeedsChanging = false; return true; } diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h index 50c1432..a3464d4 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h @@ -344,6 +344,7 @@ public: */ QGLEngineSharedShaders(const QGLContext *context); + ~QGLEngineSharedShaders(); QGLShaderProgram *simpleProgram() { return simpleShaderProg; } QGLShaderProgram *blitProgram() { return blitShaderProg; } @@ -454,7 +455,7 @@ public: // There are optimisations we can do, depending on the brush transform: // 1) May not have to apply perspective-correction // 2) Can use lower precision for matrix - void optimiseForBrushTransform(const QTransform &transform); + void optimiseForBrushTransform(QTransform::TransformationType transformType); void setSrcPixelType(Qt::BrushStyle); void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images void setOpacityMode(OpacityMode); @@ -463,11 +464,14 @@ public: void setCustomStage(QGLCustomShaderStage* stage); void removeCustomStage(); - uint getUniformLocation(Uniform id); + GLuint getUniformLocation(Uniform id); void setDirty(); // someone has manually changed the current shader program bool useCorrectShaderProg(); // returns true if the shader program needed to be changed + void useSimpleProgram(); + void useBlitProgram(); + QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer diff --git a/src/opengl/gl2paintengineex/qglengineshadersource_p.h b/src/opengl/gl2paintengineex/qglengineshadersource_p.h index 2407979..46de124 100644 --- a/src/opengl/gl2paintengineex/qglengineshadersource_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h @@ -99,12 +99,15 @@ static const char* const qglslMainWithTexCoordsAndOpacityVertexShader = "\ opacity = opacityArray; \ }"; +// NOTE: We let GL do the perspective correction so texture lookups in the fragment +// shader are also perspective corrected. static const char* const qglslPositionOnlyVertexShader = "\ - attribute highp vec4 vertexCoordsArray;\ - uniform highp mat4 pmvMatrix;\ + attribute highp vec2 vertexCoordsArray;\ + uniform highp mat3 pmvMatrix;\ void setPosition(void)\ {\ - gl_Position = pmvMatrix * vertexCoordsArray;\ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \ + gl_Position = vec4(transformedPos.xy, 0.0, transformedPos.z); \ }"; static const char* const qglslUntransformedPositionVertexShader = "\ @@ -116,20 +119,19 @@ static const char* const qglslUntransformedPositionVertexShader = "\ // Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125 static const char* const qglslPositionWithPatternBrushVertexShader = "\ - attribute highp vec4 vertexCoordsArray; \ - uniform highp mat4 pmvMatrix; \ + attribute highp vec2 vertexCoordsArray; \ + uniform highp mat3 pmvMatrix; \ uniform mediump vec2 halfViewportSize; \ uniform highp vec2 invertedTextureSize; \ uniform highp mat3 brushTransform; \ varying highp vec2 patternTexCoords; \ void setPosition(void) { \ - gl_Position = pmvMatrix * vertexCoordsArray;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \ + gl_Position.xy = transformedPos.xy / transformedPos.z; \ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1.0); \ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ + gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \ patternTexCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \ }"; @@ -147,20 +149,19 @@ static const char* const qglslPatternBrushSrcFragmentShader = "\ // Linear Gradient Brush static const char* const qglslPositionWithLinearGradientBrushVertexShader = "\ - attribute highp vec4 vertexCoordsArray; \ - uniform highp mat4 pmvMatrix; \ + attribute highp vec2 vertexCoordsArray; \ + uniform highp mat3 pmvMatrix; \ uniform mediump vec2 halfViewportSize; \ uniform highp vec3 linearData; \ uniform highp mat3 brushTransform; \ varying mediump float index; \ void setPosition() { \ - gl_Position = pmvMatrix * vertexCoordsArray;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \ + gl_Position.xy = transformedPos.xy / transformedPos.z; \ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ + gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \ index = (dot(linearData.xy, hTexCoords.xy) * linearData.z) * invertedHTexCoordsZ; \ }"; @@ -178,20 +179,19 @@ static const char* const qglslLinearGradientBrushSrcFragmentShader = "\ // Conical Gradient Brush static const char* const qglslPositionWithConicalGradientBrushVertexShader = "\ - attribute highp vec4 vertexCoordsArray;\ - uniform highp mat4 pmvMatrix;\ + attribute highp vec2 vertexCoordsArray;\ + uniform highp mat3 pmvMatrix;\ uniform mediump vec2 halfViewportSize; \ uniform highp mat3 brushTransform; \ varying highp vec2 A; \ void setPosition(void)\ {\ - gl_Position = pmvMatrix * vertexCoordsArray;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \ + gl_Position.xy = transformedPos.xy / transformedPos.z; \ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ + gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \ A = hTexCoords.xy * invertedHTexCoordsZ; \ }"; @@ -215,8 +215,8 @@ static const char* const qglslConicalGradientBrushSrcFragmentShader = "\n\ // Radial Gradient Brush static const char* const qglslPositionWithRadialGradientBrushVertexShader = "\ - attribute highp vec4 vertexCoordsArray;\ - uniform highp mat4 pmvMatrix;\ + attribute highp vec2 vertexCoordsArray;\ + uniform highp mat3 pmvMatrix;\ uniform mediump vec2 halfViewportSize; \ uniform highp mat3 brushTransform; \ uniform highp vec2 fmp; \ @@ -224,13 +224,12 @@ static const char* const qglslPositionWithRadialGradientBrushVertexShader = "\ varying highp vec2 A; \ void setPosition(void) \ {\ - gl_Position = pmvMatrix * vertexCoordsArray;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \ + gl_Position.xy = transformedPos.xy / transformedPos.z; \ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ + gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \ A = hTexCoords.xy * invertedHTexCoordsZ; \ b = 2.0 * dot(A, fmp); \ }"; @@ -253,20 +252,19 @@ static const char* const qglslRadialGradientBrushSrcFragmentShader = "\ // Texture Brush static const char* const qglslPositionWithTextureBrushVertexShader = "\ - attribute highp vec4 vertexCoordsArray; \ - uniform highp mat4 pmvMatrix; \ + attribute highp vec2 vertexCoordsArray; \ + uniform highp mat3 pmvMatrix; \ uniform mediump vec2 halfViewportSize; \ uniform highp vec2 invertedTextureSize; \ uniform highp mat3 brushTransform; \ varying highp vec2 textureCoords; \ void setPosition(void) { \ - gl_Position = pmvMatrix * vertexCoordsArray;\ - gl_Position.xy = gl_Position.xy / gl_Position.w; \ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \ + gl_Position.xy = transformedPos.xy / transformedPos.z; \ mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \ mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \ - gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \ - gl_Position.w = invertedHTexCoordsZ; \ + gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \ textureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \ }"; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 3fce384..5901601 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -75,15 +75,14 @@ #include <QPaintEngine> #include <private/qpainter_p.h> #include <private/qfontengine_p.h> -#include <private/qtextureglyphcache_p.h> #include <private/qpixmapdata_gl_p.h> #include <private/qdatabuffer_p.h> #include "qglgradientcache_p.h" #include "qglengineshadermanager_p.h" #include "qgl2pexvertexarray_p.h" - #include "qtriangulatingstroker_p.h" +#include "qtextureglyphcache_gl_p.h" #include <QDebug> @@ -91,254 +90,6 @@ QT_BEGIN_NAMESPACE //#define QT_GL_NO_SCISSOR_TEST -static const GLuint GL_STENCIL_HIGH_BIT = 0x80; -static const GLuint QT_BRUSH_TEXTURE_UNIT = 0; -static const GLuint QT_IMAGE_TEXTURE_UNIT = 0; //Can be the same as brush texture unit -static const GLuint QT_MASK_TEXTURE_UNIT = 1; -static const GLuint QT_BACKGROUND_TEXTURE_UNIT = 2; - -#ifdef Q_WS_WIN -extern Q_GUI_EXPORT bool qt_cleartype_enabled; -#endif - -class QGLTextureGlyphCache : public QObject, public QTextureGlyphCache -{ - Q_OBJECT -public: - QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix); - ~QGLTextureGlyphCache(); - - virtual void createTextureData(int width, int height); - virtual void resizeTextureData(int width, int height); - virtual void fillTexture(const Coord &c, glyph_t glyph); - virtual int glyphMargin() const; - - inline GLuint texture() const { return m_texture; } - - inline int width() const { return m_width; } - inline int height() const { return m_height; } - - inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; } - - -public Q_SLOTS: - void contextDestroyed(const QGLContext *context) { - if (context == ctx) { - QList<const QGLContext *> shares = qgl_share_reg()->shares(ctx); - if (shares.isEmpty()) { - glDeleteFramebuffers(1, &m_fbo); - if (m_width || m_height) - glDeleteTextures(1, &m_texture); - ctx = 0; - } else { - // since the context holding the texture is shared, and - // about to be destroyed, we have to transfer ownership - // of the texture to one of the share contexts - ctx = const_cast<QGLContext *>((ctx == shares.at(0)) ? shares.at(1) : shares.at(0)); - } - } - } - -private: - QGLContext *ctx; - - QGL2PaintEngineExPrivate *pex; - - GLuint m_texture; - GLuint m_fbo; - - int m_width; - int m_height; - - QGLShaderProgram *m_program; -}; - -QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix) - : QTextureGlyphCache(type, matrix) - , ctx(context) - , m_width(0) - , m_height(0) -{ - glGenFramebuffers(1, &m_fbo); - connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)), - SLOT(contextDestroyed(const QGLContext*))); -} - -QGLTextureGlyphCache::~QGLTextureGlyphCache() -{ - if (ctx) { - QGLShareContextScope scope(ctx); - glDeleteFramebuffers(1, &m_fbo); - - if (m_width || m_height) - glDeleteTextures(1, &m_texture); - } -} - -void QGLTextureGlyphCache::createTextureData(int width, int height) -{ - glGenTextures(1, &m_texture); - glBindTexture(GL_TEXTURE_2D, m_texture); - - m_width = width; - m_height = height; - - QVarLengthArray<uchar> data(width * height); - for (int i = 0; i < data.size(); ++i) - data[i] = 0; - - if (m_type == QFontEngineGlyphCache::Raster_RGBMask) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]); - else - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -} - -void QGLTextureGlyphCache::resizeTextureData(int width, int height) -{ - // ### the QTextureGlyphCache API needs to be reworked to allow - // ### resizeTextureData to fail - - int oldWidth = m_width; - int oldHeight = m_height; - - GLuint oldTexture = m_texture; - createTextureData(width, height); - - glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo); - - GLuint tmp_texture; - glGenTextures(1, &tmp_texture); - glBindTexture(GL_TEXTURE_2D, tmp_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glBindTexture(GL_TEXTURE_2D, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, tmp_texture, 0); - - glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - glBindTexture(GL_TEXTURE_2D, oldTexture); - - pex->transferMode(BrushDrawingMode); - -#ifndef QT_OPENGL_ES_2 - if (pex->inRenderText) - glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_SCISSOR_BIT); -#endif - - glDisable(GL_STENCIL_TEST); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - - glViewport(0, 0, oldWidth, oldHeight); - - float vertexCoordinateArray[] = { -1, -1, 1, -1, 1, 1, -1, 1 }; - float textureCoordinateArray[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; - - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray); - glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray); - - pex->shaderManager->blitProgram()->bind(); - pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); - pex->shaderManager->setDirty(); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - - glBindTexture(GL_TEXTURE_2D, m_texture); - -#ifdef QT_OPENGL_ES_2 - QDataBuffer<uchar> buffer(4*oldWidth*oldHeight); - buffer.resize(4*oldWidth*oldHeight); - glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data()); - - // do an in-place conversion from GL_RGBA to GL_ALPHA - for (int i=0; i<oldWidth*oldHeight; ++i) - buffer.data()[i] = buffer.at(4*i + 3); - - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, - GL_ALPHA, GL_UNSIGNED_BYTE, buffer.data()); -#else - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); -#endif - - glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_RENDERBUFFER_EXT, 0); - glDeleteTextures(1, &tmp_texture); - glDeleteTextures(1, &oldTexture); - - glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); - - glViewport(0, 0, pex->width, pex->height); - pex->updateClipScissorTest(); - -#ifndef QT_OPENGL_ES_2 - if (pex->inRenderText) - glPopAttrib(); -#endif -} - -void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) -{ - QImage mask = textureMapForGlyph(glyph); - const int maskWidth = mask.width(); - const int maskHeight = mask.height(); - - if (mask.format() == QImage::Format_Mono) { - mask = mask.convertToFormat(QImage::Format_Indexed8); - for (int y = 0; y < maskHeight; ++y) { - uchar *src = (uchar *) mask.scanLine(y); - for (int x = 0; x < maskWidth; ++x) - src[x] = -src[x]; // convert 0 and 1 into 0 and 255 - } - } - - - glBindTexture(GL_TEXTURE_2D, m_texture); - if (mask.format() == QImage::Format_RGB32) { - glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits()); - } else { -#ifdef QT_OPENGL_ES2 - glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits()); -#else - // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is - // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista - // and nVidia GeForce 8500GT. GL_UNPACK_ALIGNMENT is set to four bytes, 'mask' has a - // multiple of four bytes per line, and most of the glyph shows up correctly in the - // texture, which makes me think that this is a driver bug. - // One workaround is to make sure the mask width is a multiple of four bytes, for instance - // by converting it to a format with four bytes per pixel. Another is to copy one line at a - // time. - - for (int i = 0; i < maskHeight; ++i) - glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i)); -#endif - } -} - -int QGLTextureGlyphCache::glyphMargin() const -{ -#if defined(Q_WS_MAC) - return 2; -#elif defined (Q_WS_X11) - return 0; -#else - return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0; -#endif -} - extern QImage qt_imageForBrush(int brushStyle, bool invert); ////////////////////////////////// Private Methods ////////////////////////////////////////// @@ -358,10 +109,10 @@ QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate() void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id) { // glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit? - if (id != GLuint(-1) && id == lastTexture) + if (id != GLuint(-1) && id == lastTextureUsed) return; - lastTexture = id; + lastTextureUsed = id; if (smoothPixmapTransform) { glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -386,32 +137,41 @@ inline QColor qt_premultiplyColor(QColor c, GLfloat opacity) } -void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush) +void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush) { + if (qbrush_fast_equals(currentBrush, brush)) + return; + + const Qt::BrushStyle newStyle = qbrush_style(brush); + Q_ASSERT(newStyle != Qt::NoBrush); + currentBrush = brush; - brushTextureDirty = true; - brushUniformsDirty = true; - if (currentBrush->style() == Qt::TexturePattern - && qHasPixmapTexture(*brush) && brush->texture().isQBitmap()) + brushUniformsDirty = true; // All brushes have at least one uniform + + if (newStyle > Qt::SolidPattern) + brushTextureDirty = true; + + if (currentBrush.style() == Qt::TexturePattern + && qHasPixmapTexture(brush) && brush.texture().isQBitmap()) { shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern); } else { - shaderManager->setSrcPixelType(currentBrush->style()); + shaderManager->setSrcPixelType(newStyle); } - shaderManager->optimiseForBrushTransform(currentBrush->transform()); + shaderManager->optimiseForBrushTransform(currentBrush.transform().type()); } void QGL2PaintEngineExPrivate::useSimpleShader() { - shaderManager->simpleProgram()->bind(); - shaderManager->setDirty(); + shaderManager->useSimpleProgram(); if (matrixDirty) updateMatrix(); if (simpleShaderMatrixUniformDirty) { - shaderManager->simpleProgram()->setUniformValue("pmvMatrix", pmvMatrix); + const GLuint location = shaderManager->simpleProgram()->uniformLocation("pmvMatrix"); + glUniformMatrix3fv(location, 1, GL_FALSE, (GLfloat*)pmvMatrix); simpleShaderMatrixUniformDirty = false; } } @@ -420,7 +180,7 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() { Q_Q(QGL2PaintEngineEx); // qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()"); - Qt::BrushStyle style = currentBrush->style(); + Qt::BrushStyle style = currentBrush.style(); if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) { // Get the image data for the pattern @@ -433,7 +193,7 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { // Gradiant brush: All the gradiants use the same texture - const QGradient* g = currentBrush->gradient(); + const QGradient* g = currentBrush.gradient(); // We apply global opacity in the fragment shaders, so we always pass 1.0 // for opacity to the cache. @@ -450,7 +210,7 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform); } else if (style == Qt::TexturePattern) { - const QPixmap& texPixmap = currentBrush->texture(); + const QPixmap& texPixmap = currentBrush.texture(); glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); @@ -464,15 +224,15 @@ void QGL2PaintEngineExPrivate::updateBrushTexture() void QGL2PaintEngineExPrivate::updateBrushUniforms() { // qDebug("QGL2PaintEngineExPrivate::updateBrushUniforms()"); - Qt::BrushStyle style = currentBrush->style(); + Qt::BrushStyle style = currentBrush.style(); if (style == Qt::NoBrush) return; - QTransform brushQTransform = currentBrush->transform(); + QTransform brushQTransform = currentBrush.transform(); if (style == Qt::SolidPattern) { - QColor col = qt_premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity); + QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::FragmentColor), col); } else { @@ -480,7 +240,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() QPointF translationPoint; if (style <= Qt::DiagCrossPattern) { - QColor col = qt_premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity); + QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); @@ -488,7 +248,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); } else if (style == Qt::LinearGradientPattern) { - const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush->gradient()); + const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush.gradient()); QPointF realStart = g->start(); QPointF realFinal = g->finalStop(); @@ -508,7 +268,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); } else if (style == Qt::ConicalGradientPattern) { - const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush->gradient()); + const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush.gradient()); translationPoint = g->center(); GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0; @@ -519,7 +279,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); } else if (style == Qt::RadialGradientPattern) { - const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush->gradient()); + const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush.gradient()); QPointF realCenter = g->center(); QPointF realFocal = g->focalPoint(); qreal realRadius = g->radius(); @@ -537,10 +297,10 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); } else if (style == Qt::TexturePattern) { - const QPixmap& texPixmap = currentBrush->texture(); + const QPixmap& texPixmap = currentBrush.texture(); - if (qHasPixmapTexture(*currentBrush) && currentBrush->texture().isQBitmap()) { - QColor col = qt_premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity); + if (qHasPixmapTexture(currentBrush) && currentBrush.texture().isQBitmap()) { + QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); } @@ -561,7 +321,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() QTransform gl_to_qt(1, 0, 0, -1, 0, height); QTransform inv_matrix; if (style == Qt::TexturePattern && textureInvertedY == -1) - inv_matrix = gl_to_qt * (QTransform(1, 0, 0, -1, 0, currentBrush->texture().height()) * brushQTransform * matrix).inverted() * translate; + inv_matrix = gl_to_qt * (QTransform(1, 0, 0, -1, 0, currentBrush.texture().height()) * brushQTransform * matrix).inverted() * translate; else inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate; @@ -577,66 +337,59 @@ void QGL2PaintEngineExPrivate::updateMatrix() { // qDebug("QGL2PaintEngineExPrivate::updateMatrix()"); - // We set up the 4x4 transformation matrix on the vertex shaders to - // be the equivalent of glOrtho(0, w, h, 0, -1, 1) * transform: + const QTransform& transform = q->state()->matrix; + + // The projection matrix converts from Qt's coordinate system to GL's coordinate system + // * GL's viewport is 2x2, Qt's is width x height + // * GL has +y -> -y going from bottom -> top, Qt is the other way round + // * GL has [0,0] in the center, Qt has it in the top-left // - // | 2/width 0 0 -1 | | m11 m21 0 dx | - // | 0 -2/height 0 1 | | m12 m22 0 dy | - // | 0 0 -1 0 | * | 0 0 1 0 | - // | 0 0 0 1 | | m13 m23 0 m33 | + // This results in the Projection matrix below, which is multiplied by the painter's + // transformation matrix, as shown below: // - // We expand out the multiplication to save the cost of a full 4x4 - // matrix multiplication as most of the components are trivial. - const QTransform& transform = q->state()->matrix; + // Projection Matrix Painter Transform + // ------------------------------------------------ ------------------------ + // | 2.0 / width | 0.0 | -1.0 | | m11 | m21 | dx | + // | 0.0 | -2.0 / height | 1.0 | * | m12 | m22 | dy | + // | 0.0 | 0.0 | 1.0 | | m13 | m23 | m33 | + // ------------------------------------------------ ------------------------ + // + // NOTE: The resultant matrix is also transposed, as GL expects column-major matracies + + const GLfloat wfactor = 2.0f / width; + const GLfloat hfactor = -2.0f / height; + GLfloat dx = transform.dx(); + GLfloat dy = transform.dy(); + + // Non-integer translates can have strange effects for some rendering operations such as + // anti-aliased text rendering. In such cases, we snap the translate to the pixel grid. + if (snapToPixelGrid && transform.type() == QTransform::TxTranslate) { + // 0.50 needs to rounded down to 0.0 for consistency with raster engine: + dx = ceilf(dx - 0.5f); + dy = ceilf(dy - 0.5f); + } - if (mode == TextDrawingMode) { - // Text drawing mode is only used for non-scaling transforms - pmvMatrix[0][0] = 2.0 / width; - pmvMatrix[0][1] = 0.0; - pmvMatrix[0][2] = 0.0; - pmvMatrix[0][3] = 0.0; - pmvMatrix[1][0] = 0.0; - pmvMatrix[1][1] = -2.0 / height; - pmvMatrix[1][2] = 0.0; - pmvMatrix[1][3] = 0.0; - pmvMatrix[2][0] = 0.0; - pmvMatrix[2][1] = 0.0; - pmvMatrix[2][2] = -1.0; - pmvMatrix[2][3] = 0.0; - pmvMatrix[3][0] = pmvMatrix[0][0] * qRound(transform.dx()) - 1.0; - pmvMatrix[3][1] = pmvMatrix[1][1] * qRound(transform.dy()) + 1.0; - pmvMatrix[3][2] = 0.0; - pmvMatrix[3][3] = 1.0; - - inverseScale = 1; - } else { - qreal wfactor = 2.0 / width; - qreal hfactor = -2.0 / height; - - pmvMatrix[0][0] = wfactor * transform.m11() - transform.m13(); - pmvMatrix[0][1] = hfactor * transform.m12() + transform.m13(); - pmvMatrix[0][2] = 0.0; - pmvMatrix[0][3] = transform.m13(); - pmvMatrix[1][0] = wfactor * transform.m21() - transform.m23(); - pmvMatrix[1][1] = hfactor * transform.m22() + transform.m23(); - pmvMatrix[1][2] = 0.0; - pmvMatrix[1][3] = transform.m23(); - pmvMatrix[2][0] = 0.0; - pmvMatrix[2][1] = 0.0; - pmvMatrix[2][2] = -1.0; - pmvMatrix[2][3] = 0.0; - pmvMatrix[3][0] = wfactor * transform.dx() - transform.m33(); - pmvMatrix[3][1] = hfactor * transform.dy() + transform.m33(); - pmvMatrix[3][2] = 0.0; - pmvMatrix[3][3] = transform.m33(); - - // 1/10000 == 0.0001, so we have good enough res to cover curves - // that span the entire widget... - inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), - qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), - qreal(0.0001)); + if (addOffset) { + dx += 0.49f; + dy += 0.49f; } + pmvMatrix[0][0] = (wfactor * transform.m11()) - transform.m13(); + pmvMatrix[1][0] = (wfactor * transform.m21()) - transform.m23(); + pmvMatrix[2][0] = (wfactor * dx) - transform.m33(); + pmvMatrix[0][1] = (hfactor * transform.m12()) + transform.m13(); + pmvMatrix[1][1] = (hfactor * transform.m22()) + transform.m23(); + pmvMatrix[2][1] = (hfactor * dy) + transform.m33(); + pmvMatrix[0][2] = transform.m13(); + pmvMatrix[1][2] = transform.m23(); + pmvMatrix[2][2] = transform.m33(); + + // 1/10000 == 0.0001, so we have good enough res to cover curves + // that span the entire widget... + inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), + qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), + qreal(0.0001)); + matrixDirty = false; // The actual data has been updated so both shader program's uniforms need updating @@ -716,7 +469,19 @@ static inline void setCoords(GLfloat *coords, const QGLRect &rect) void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern) { // Setup for texture drawing + currentBrush = noBrush; shaderManager->setSrcPixelType(pattern ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc); + + if (addOffset) { + addOffset = false; + matrixDirty = true; + } + + if (snapToPixelGrid) { + snapToPixelGrid = false; + matrixDirty = true; + } + if (prepareForDraw(opaque)) shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); @@ -745,6 +510,10 @@ void QGL2PaintEngineEx::beginNativePainting() QGLContext *ctx = d->ctx; glUseProgram(0); + // Disable all the vertex attribute arrays: + for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) + glDisableVertexAttribArray(i); + #ifndef QT_OPENGL_ES_2 // be nice to people who mix OpenGL 1.x code with QPainter commands // by setting modelview and projection matrices to mirror the GL 1 @@ -771,7 +540,7 @@ void QGL2PaintEngineEx::beginNativePainting() Q_UNUSED(ctx); #endif - d->lastTexture = GLuint(-1); + d->lastTextureUsed = GLuint(-1); d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); d->resetGLState(); @@ -798,51 +567,26 @@ void QGL2PaintEngineEx::endNativePainting() d->needsSync = true; } -const QGLContext *QGL2PaintEngineEx::context() -{ - Q_D(QGL2PaintEngineEx); - return d->ctx; -} - void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) { if (newMode == mode) return; if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) { - glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glDisableVertexAttribArray(QT_OPACITY_ATTR); - - lastTexture = GLuint(-1); + lastTextureUsed = GLuint(-1); } - if (mode == TextDrawingMode) - matrixDirty = true; - if (newMode == TextDrawingMode) { - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); - - matrixDirty = true; } if (newMode == ImageDrawingMode) { - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticVertexCoordinateArray); glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticTextureCoordinateArray); } if (newMode == ImageArrayDrawingMode) { - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); - glEnableVertexAttribArray(QT_OPACITY_ATTR); - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); glVertexAttribPointer(QT_OPACITY_ATTR, 1, GL_FLOAT, GL_FALSE, 0, opacityArray.data()); @@ -867,13 +611,14 @@ struct QGL2PEVectorPathCache qreal iscale; }; -void qopengl2paintengine_cleanup_vectorpath(QPaintEngineEx *engine, void *data) +void QGL2PaintEngineExPrivate::cleanupVectorPath(QPaintEngineEx *engine, void *data) { QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data; #ifdef QT_OPENGL_CACHE_AS_VBOS - QGL2PaintEngineExPrivate *d = QGL2PaintEngineExPrivate::getData((QGL2PaintEngineEx *) engine); - d->unusedVBOSToClean << c->vbo; + Q_ASSERT(engine->type() == QPaintEngine::OpenGL2); + static_cast<QGL2PaintEngineEx *>(engine)->d_func()->unusedVBOSToClean << c->vbo; #else + Q_UNUSED(engine); qFree(c->vertices); #endif delete c; @@ -884,6 +629,21 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) { transferMode(BrushDrawingMode); + const QOpenGL2PaintEngineState *s = q->state(); + const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) && + (qbrush_style(currentBrush) == Qt::SolidPattern) && + !multisamplingAlwaysEnabled; + + if (addOffset != newAddOffset) { + addOffset = newAddOffset; + matrixDirty = true; + } + + if (snapToPixelGrid) { + snapToPixelGrid = false; + matrixDirty = true; + } + // Might need to call updateMatrix to re-calculate inverseScale if (matrixDirty) updateMatrix(); @@ -893,7 +653,7 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) // Check to see if there's any hints if (path.shape() == QVectorPath::RectangleHint) { QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y()); - prepareForDraw(currentBrush->isOpaque()); + prepareForDraw(currentBrush.isOpaque()); composite(rect); } else if (path.isConvex()) { @@ -919,7 +679,7 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) } else { cache = new QGL2PEVectorPathCache; cache->vertexCount = 0; - data = const_cast<QVectorPath &>(path).addCacheData(q, cache, qopengl2paintengine_cleanup_vectorpath); + data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath); } // Flatten the path at the current scale factor and fill it into the cache struct. @@ -930,7 +690,7 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) int floatSizeInBytes = vertexCount * 2 * sizeof(float); cache->vertexCount = vertexCount; cache->primitiveType = GL_TRIANGLE_FAN; - cache->iscale = inverseScale; + cache->iscale = inverseScale; #ifdef QT_OPENGL_CACHE_AS_VBOS glGenBuffers(1, &cache->vbo); glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); @@ -941,8 +701,7 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) #endif } - prepareForDraw(currentBrush->isOpaque()); - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + prepareForDraw(currentBrush.isOpaque()); #ifdef QT_OPENGL_CACHE_AS_VBOS glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0); @@ -960,7 +719,7 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) path.makeCacheable(); vertexCoordinateArray.clear(); vertexCoordinateArray.addPath(path, inverseScale, false); - prepareForDraw(currentBrush->isOpaque()); + prepareForDraw(currentBrush.isOpaque()); drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); } @@ -984,20 +743,11 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) // Pass when high bit is set, replace stencil value with 0 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); } - - prepareForDraw(currentBrush->isOpaque()); - - if (inRenderText) - prepareDepthRangeForRenderText(); + prepareForDraw(currentBrush.isOpaque()); // Stencil the brush onto the dest buffer composite(vertexCoordinateArray.boundingRect()); - - if (inRenderText) - restoreDepthRangeForRenderText(); - glStencilMask(0); - updateClipScissorTest(); } } @@ -1036,13 +786,6 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data, useSimpleShader(); glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d -#ifndef QT_OPENGL_ES_2 - if (inRenderText) { - glPushAttrib(GL_ENABLE_BIT); - glDisable(GL_DEPTH_TEST); - } -#endif - if (mode == WindingFillMode) { Q_ASSERT(stops && !count); if (q->state()->clipTestEnabled) { @@ -1083,10 +826,8 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data, glStencilMask(GL_STENCIL_HIGH_BIT); #if 0 glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); glDrawArrays(GL_TRIANGLE_STRIP, 0, count); - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); #else glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); @@ -1096,21 +837,13 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data, } else { glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff); } - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); glDrawArrays(GL_TRIANGLE_STRIP, 0, count); - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); #endif } // Enable color writes & disable stencil writes glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - -#ifndef QT_OPENGL_ES_2 - if (inRenderText) - glPopAttrib(); -#endif - } /* @@ -1182,10 +915,10 @@ bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) : QGLEngineShaderManager::NoOpacity; if (stateHasOpacity && (mode != ImageDrawingMode)) { // Using a brush - bool brushIsPattern = (currentBrush->style() >= Qt::Dense1Pattern) && - (currentBrush->style() <= Qt::DiagCrossPattern); + bool brushIsPattern = (currentBrush.style() >= Qt::Dense1Pattern) && + (currentBrush.style() <= Qt::DiagCrossPattern); - if ((currentBrush->style() == Qt::SolidPattern) || brushIsPattern) + if ((currentBrush.style() == Qt::SolidPattern) || brushIsPattern) opacityMode = QGLEngineShaderManager::NoOpacity; // Global opacity handled by srcPixel shader } } @@ -1204,7 +937,7 @@ bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) updateBrushUniforms(); if (shaderMatrixUniformDirty) { - shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PmvMatrix), pmvMatrix); + glUniformMatrix3fv(location(QGLEngineShaderManager::PmvMatrix), 1, GL_FALSE, (GLfloat*)pmvMatrix); shaderMatrixUniformDirty = false; } @@ -1226,12 +959,8 @@ void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect) boundingRect.right, boundingRect.top }; - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, rectVerts); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); } // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans. @@ -1239,7 +968,6 @@ void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, i GLenum primitive) { // Now setup the pointer to the vertex array: - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); int previousStop = 0; @@ -1253,31 +981,6 @@ void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, i glDrawArrays(primitive, previousStop, stop - previousStop); previousStop = stop; } - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); -} - -void QGL2PaintEngineExPrivate::prepareDepthRangeForRenderText() -{ -#ifndef QT_OPENGL_ES_2 - // Get the z translation value from the model view matrix and - // transform it using the ortogonal projection with z-near = 0, - // and z-far = 1, which is used in QGLWidget::renderText() - GLdouble model[4][4]; - glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]); - float deviceZ = -2 * model[3][2] - 1; - - glGetFloatv(GL_DEPTH_RANGE, depthRange); - float windowZ = depthRange[0] + (deviceZ + 1) * 0.5 * (depthRange[1] - depthRange[0]); - - glDepthRange(windowZ, windowZ); -#endif -} - -void QGL2PaintEngineExPrivate::restoreDepthRangeForRenderText() -{ -#ifndef QT_OPENGL_ES_2 - glDepthRange(depthRange[0], depthRange[1]); -#endif } /////////////////////////////////// Public Methods ////////////////////////////////////////// @@ -1295,31 +998,11 @@ void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush) { Q_D(QGL2PaintEngineEx); - Qt::BrushStyle style = qbrush_style(brush); - if (style == Qt::NoBrush) + if (qbrush_style(brush) == Qt::NoBrush) return; - if (!d->inRenderText) - ensureActive(); - - QOpenGL2PaintEngineState *s = state(); - bool doOffset = !(s->renderHints & QPainter::Antialiasing) && - (style == Qt::SolidPattern) && - !d->multisamplingAlwaysEnabled; - - if (doOffset) { - d->temporaryTransform = s->matrix; - QTransform tx = QTransform::fromTranslate(.49, .49); - s->matrix = s->matrix * tx; - d->matrixDirty = true; - } - - d->setBrush(&brush); + ensureActive(); + d->setBrush(brush); d->fill(path); - - if (doOffset) { - s->matrix = d->temporaryTransform; - d->matrixDirty = true; - } } extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp @@ -1329,9 +1012,8 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) { Q_D(QGL2PaintEngineEx); - Qt::PenStyle penStyle = qpen_style(pen); const QBrush &penBrush = qpen_brush(pen); - if (penStyle == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush) + if (qpen_style(pen) == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush) return; QOpenGL2PaintEngineState *s = state(); @@ -1342,53 +1024,57 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) } ensureActive(); + d->setBrush(penBrush); + d->stroke(path, pen); +} - bool doOffset = !(s->renderHints & QPainter::Antialiasing) && !d->multisamplingAlwaysEnabled; - if (doOffset) { - d->temporaryTransform = s->matrix; - QTransform tx = QTransform::fromTranslate(0.49, .49); - s->matrix = s->matrix * tx; - d->matrixDirty = true; +void QGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen) +{ + const QOpenGL2PaintEngineState *s = q->state(); + const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) && !multisamplingAlwaysEnabled; + if (addOffset != newAddOffset) { + addOffset = newAddOffset; + matrixDirty = true; } - bool opaque = penBrush.isOpaque() && s->opacity > 0.99; - d->setBrush(&penBrush); - d->transferMode(BrushDrawingMode); + if (snapToPixelGrid) { + snapToPixelGrid = false; + matrixDirty = true; + } + + const Qt::PenStyle penStyle = qpen_style(pen); + const QBrush &penBrush = qpen_brush(pen); + const bool opaque = penBrush.isOpaque() && s->opacity > 0.99; + + transferMode(BrushDrawingMode); // updateMatrix() is responsible for setting the inverse scale on // the strokers, so we need to call it here and not wait for // prepareForDraw() down below. - d->updateMatrix(); + updateMatrix(); if (penStyle == Qt::SolidLine) { - d->stroker.process(path, pen); + stroker.process(path, pen); } else { // Some sort of dash - d->dasher.process(path, pen); + dasher.process(path, pen); - QVectorPath dashStroke(d->dasher.points(), - d->dasher.elementCount(), - d->dasher.elementTypes()); - d->stroker.process(dashStroke, pen); + QVectorPath dashStroke(dasher.points(), + dasher.elementCount(), + dasher.elementTypes()); + stroker.process(dashStroke, pen); } - - QGLContext *ctx = d->ctx; - Q_UNUSED(ctx); - if (opaque) { - d->prepareForDraw(opaque); - glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, d->stroker.vertices()); - glDrawArrays(GL_TRIANGLE_STRIP, 0, d->stroker.vertexCount() / 2); + prepareForDraw(opaque); + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, stroker.vertices()); + glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2); // QBrush b(Qt::green); // d->setBrush(&b); // d->prepareForDraw(true); // glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2); - glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - } else { qreal width = qpen_widthf(pen) / 2; if (width == 0) @@ -1398,30 +1084,25 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) : width; if (pen.isCosmetic()) - extra = extra * d->inverseScale; + extra = extra * inverseScale; QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra); - d->fillStencilWithVertexArray(d->stroker.vertices(), d->stroker.vertexCount() / 2, + fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2, 0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode); glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); // Pass when any bit is set, replace stencil value with 0 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); - d->prepareForDraw(false); + prepareForDraw(false); // Stencil the brush onto the dest buffer - d->composite(bounds); + composite(bounds); glStencilMask(0); - d->updateClipScissorTest(); - } - - if (doOffset) { - s->matrix = d->temporaryTransform; - d->matrixDirty = true; + updateClipScissorTest(); } } @@ -1461,7 +1142,7 @@ void QGL2PaintEngineEx::renderHintsChanged() #endif Q_D(QGL2PaintEngineEx); - d->lastTexture = GLuint(-1); + d->lastTextureUsed = GLuint(-1); d->brushTextureDirty = true; // qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!"); } @@ -1539,27 +1220,26 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem { Q_D(QGL2PaintEngineEx); - if (!d->inRenderText) - ensureActive(); + ensureActive(); QOpenGL2PaintEngineState *s = state(); const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); - bool drawCached = true; + QTransform::TransformationType txtype = s->matrix.type(); - if (s->matrix.type() > QTransform::TxTranslate) - drawCached = false; + float det = s->matrix.determinant(); + bool drawCached = txtype < QTransform::TxProject; - // don't try to cache huge fonts + // don't try to cache huge fonts or vastly transformed fonts const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) >= 64 * 64) + if (pixelSize * pixelSize * qAbs(det) >= 64 * 64 || det < 0.25f || det > 4.f) drawCached = false; QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) : d->glyphCacheType; - if (d->inRenderText) + if (txtype > QTransform::TxTranslate) glyphType = QFontEngineGlyphCache::Raster_A8; if (glyphType == QFontEngineGlyphCache::Raster_RGBMask @@ -1581,7 +1261,6 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly const QTextItemInt &ti) { Q_Q(QGL2PaintEngineEx); - QOpenGL2PaintEngineState *s = q->state(); QVarLengthArray<QFixedPoint> positions; QVarLengthArray<glyph_t> glyphs; @@ -1589,10 +1268,10 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); QGLTextureGlyphCache *cache = - (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, s->matrix); + (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform()); if (!cache || cache->cacheType() != glyphType) { - cache = new QGLTextureGlyphCache(ctx, glyphType, s->matrix); + cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); ti.fontEngine->setGlyphCache(ctx, cache); } @@ -1602,8 +1281,6 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly if (cache->width() == 0 || cache->height() == 0) return; - if (inRenderText) - transferMode(BrushDrawingMode); transferMode(TextDrawingMode); int margin = cache->glyphMargin(); @@ -1631,11 +1308,17 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr) glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); - QBrush pensBrush = q->state()->pen.brush(); - setBrush(&pensBrush); + if (addOffset) { + addOffset = false; + matrixDirty = true; + } + if (!snapToPixelGrid) { + snapToPixelGrid = true; + matrixDirty = true; + } - if (inRenderText) - prepareDepthRangeForRenderText(); + QBrush pensBrush = q->state()->pen.brush(); + setBrush(pensBrush); if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { @@ -1677,7 +1360,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly q->state()->opacity = 1; opacityUniformDirty = true; pensBrush = Qt::white; - setBrush(&pensBrush); + setBrush(pensBrush); } compositionModeDirty = false; // I can handle this myself, thank you very much @@ -1698,7 +1381,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly q->state()->opacity = oldOpacity; opacityUniformDirty = true; pensBrush = q->state()->pen.brush(); - setBrush(&pensBrush); + setBrush(pensBrush); } compositionModeDirty = false; @@ -1721,27 +1404,40 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); - - if (inRenderText) - restoreDepthRangeForRenderText(); } void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) { + Q_D(QGL2PaintEngineEx); // Use fallback for extended composition modes. if (state()->composition_mode > QPainter::CompositionMode_Plus) { QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints); return; } - Q_D(QGL2PaintEngineEx); + ensureActive(); + d->drawPixmaps(drawingData, dataCount, pixmap, hints); +} + +void QGL2PaintEngineExPrivate::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) +{ GLfloat dx = 1.0f / pixmap.size().width(); GLfloat dy = 1.0f / pixmap.size().height(); - d->vertexCoordinateArray.clear(); - d->textureCoordinateArray.clear(); - d->opacityArray.reset(); + vertexCoordinateArray.clear(); + textureCoordinateArray.clear(); + opacityArray.reset(); + + if (addOffset) { + addOffset = false; + matrixDirty = true; + } + + if (snapToPixelGrid) { + snapToPixelGrid = false; + matrixDirty = true; + } bool allOpaque = true; @@ -1758,31 +1454,28 @@ void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int d QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c); QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c); - d->vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); - d->vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y()); - d->vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); - d->vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); - d->vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y()); - d->vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); + vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); + vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y()); + vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); + vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); + vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y()); + vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy, drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy); - d->textureCoordinateArray.lineToArray(src.right, src.bottom); - d->textureCoordinateArray.lineToArray(src.right, src.top); - d->textureCoordinateArray.lineToArray(src.left, src.top); - d->textureCoordinateArray.lineToArray(src.left, src.top); - d->textureCoordinateArray.lineToArray(src.left, src.bottom); - d->textureCoordinateArray.lineToArray(src.right, src.bottom); + textureCoordinateArray.lineToArray(src.right, src.bottom); + textureCoordinateArray.lineToArray(src.right, src.top); + textureCoordinateArray.lineToArray(src.left, src.top); + textureCoordinateArray.lineToArray(src.left, src.top); + textureCoordinateArray.lineToArray(src.left, src.bottom); + textureCoordinateArray.lineToArray(src.right, src.bottom); - qreal opacity = drawingData[i].opacity * state()->opacity; - d->opacityArray << opacity << opacity << opacity << opacity << opacity << opacity; + qreal opacity = drawingData[i].opacity * q->state()->opacity; + opacityArray << opacity << opacity << opacity << opacity << opacity << opacity; allOpaque &= (opacity >= 0.99f); } - ensureActive(); - - QGLContext *ctx = d->ctx; glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption @@ -1790,27 +1483,28 @@ void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int d if (texture->options & QGLContext::InvertedYBindOption) { // Flip texture y-coordinate. - QGLPoint *data = d->textureCoordinateArray.data(); + QGLPoint *data = textureCoordinateArray.data(); for (int i = 0; i < 6 * dataCount; ++i) data[i].y = 1 - data[i].y; } - d->transferMode(ImageArrayDrawingMode); + transferMode(ImageArrayDrawingMode); bool isBitmap = pixmap.isQBitmap(); bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque; - d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, - state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); + updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, + q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); // Setup for texture drawing - d->shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc); - if (d->prepareForDraw(isOpaque)) - d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); + currentBrush = noBrush; + shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc); + if (prepareForDraw(isOpaque)) + shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); if (isBitmap) { - QColor col = qt_premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity); - d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::PatternColor), col); + QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); + shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); } glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount); @@ -1842,7 +1536,8 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->compositionModeDirty = true; d->opacityUniformDirty = true; d->needsSync = true; - d->use_system_clip = !systemClip().isEmpty(); + d->useSystemClip = !systemClip().isEmpty(); + d->currentBrush = QBrush(); d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); d->stencilClean = true; @@ -1861,11 +1556,9 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->shaderManager = new QGLEngineShaderManager(d->ctx); - if (!d->inRenderText) { - glDisable(GL_STENCIL_TEST); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - } + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); #if !defined(QT_OPENGL_ES_2) glDisable(GL_MULTISAMPLE); @@ -1875,6 +1568,7 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) #if !defined(QT_OPENGL_ES_2) #if defined(Q_WS_WIN) + extern Q_GUI_EXPORT bool qt_cleartype_enabled; if (qt_cleartype_enabled) #endif d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask; @@ -1942,6 +1636,7 @@ void QGL2PaintEngineEx::ensureActive() glViewport(0, 0, d->width, d->height); d->needsSync = false; d->shaderManager->setDirty(); + d->ctx->d_func()->syncGlState(); setState(state()); } } @@ -1962,12 +1657,12 @@ void QGL2PaintEngineExPrivate::updateClipScissorTest() #else QRect bounds = q->state()->rectangleClip; if (!q->state()->clipEnabled) { - if (use_system_clip) + if (useSystemClip) bounds = systemClip.boundingRect(); else bounds = QRect(0, 0, width, height); } else { - if (use_system_clip) + if (useSystemClip) bounds = bounds.intersected(systemClip.boundingRect()); else bounds = bounds.intersected(QRect(0, 0, width, height)); @@ -2022,6 +1717,15 @@ void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value) { transferMode(BrushDrawingMode); + if (addOffset) { + addOffset = false; + matrixDirty = true; + } + if (snapToPixelGrid) { + snapToPixelGrid = false; + matrixDirty = true; + } + if (matrixDirty) updateMatrix(); @@ -2121,7 +1825,7 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) switch (op) { case Qt::NoClip: - if (d->use_system_clip) { + if (d->useSystemClip) { state()->clipTestEnabled = true; state()->currentClip = 1; } else { @@ -2193,13 +1897,13 @@ void QGL2PaintEngineExPrivate::systemStateChanged() q->state()->clipChanged = true; if (systemClip.isEmpty()) { - use_system_clip = false; + useSystemClip = false; } else { if (q->paintDevice()->devType() == QInternal::Widget && currentClipWidget) { QWidgetPrivate *widgetPrivate = qt_widget_private(currentClipWidget->window()); - use_system_clip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter; + useSystemClip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter; } else { - use_system_clip = true; + useSystemClip = true; } } @@ -2209,19 +1913,19 @@ void QGL2PaintEngineExPrivate::systemStateChanged() q->state()->currentClip = 1; maxClip = 1; - q->state()->rectangleClip = use_system_clip ? systemClip.boundingRect() : QRect(0, 0, width, height); + q->state()->rectangleClip = useSystemClip ? systemClip.boundingRect() : QRect(0, 0, width, height); updateClipScissorTest(); if (systemClip.rectCount() == 1) { if (systemClip.boundingRect() == QRect(0, 0, width, height)) - use_system_clip = false; + useSystemClip = false; #ifndef QT_GL_NO_SCISSOR_TEST // scissoring takes care of the system clip return; #endif } - if (use_system_clip) { + if (useSystemClip) { clearClip(0); QPainterPath path; @@ -2300,12 +2004,6 @@ QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const return s; } -void QGL2PaintEngineEx::setRenderTextActive(bool active) -{ - Q_D(QGL2PaintEngineEx); - d->inRenderText = active; -} - QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other) : QPainterState(other) { @@ -2330,5 +2028,3 @@ QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState() } QT_END_NAMESPACE - -#include "qpaintengineex_opengl2.moc" diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 0084476..eaae187 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -73,6 +73,12 @@ enum EngineMode { QT_BEGIN_NAMESPACE +#define GL_STENCIL_HIGH_BIT GLuint(0x80) +#define QT_BRUSH_TEXTURE_UNIT GLuint(0) +#define QT_IMAGE_TEXTURE_UNIT GLuint(0) //Can be the same as brush texture unit +#define QT_MASK_TEXTURE_UNIT GLuint(1) +#define QT_BACKGROUND_TEXTURE_UNIT GLuint(2) + class QGL2PaintEngineExPrivate; @@ -105,13 +111,8 @@ public: ~QGL2PaintEngineEx(); bool begin(QPaintDevice *device); - bool end(); - void ensureActive(); - - virtual void fill(const QVectorPath &path, const QBrush &brush); - virtual void stroke(const QVectorPath &path, const QPen &pen); - virtual void clip(const QVectorPath &path, Qt::ClipOperation op); + bool end(); virtual void clipEnabledChanged(); virtual void penChanged(); @@ -122,20 +123,21 @@ public: virtual void renderHintsChanged(); virtual void transformChanged(); - + virtual void drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr); virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); + virtual void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints); virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlags flags = Qt::AutoColor); - virtual void drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr); - virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); + virtual void fill(const QVectorPath &path, const QBrush &brush); + virtual void stroke(const QVectorPath &path, const QPen &pen); + virtual void clip(const QVectorPath &path, Qt::ClipOperation op); - virtual void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints); Type type() const { return OpenGL2; } - void setState(QPainterState *s); - QPainterState *createState(QPainterState *orig) const; + virtual void setState(QPainterState *s); + virtual QPainterState *createState(QPainterState *orig) const; inline QOpenGL2PaintEngineState *state() { return static_cast<QOpenGL2PaintEngineState *>(QPaintEngineEx::state()); } @@ -146,8 +148,6 @@ public: void beginNativePainting(); void endNativePainting(); - const QGLContext* context(); - QPixmapFilter *pixmapFilter(int type, const QPixmapFilter *prototype); void setRenderTextActive(bool); @@ -169,12 +169,13 @@ public: QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) : q(q_ptr), + shaderManager(0), width(0), height(0), ctx(0), - currentBrush(0), - inverseScale(1), - shaderManager(0), - inRenderText(false) + useSystemClip(true), + snapToPixelGrid(false), + addOffset(false), + inverseScale(1) { } ~QGL2PaintEngineExPrivate(); @@ -185,45 +186,57 @@ public: void updateCompositionMode(); void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id = -1); - void setBrush(const QBrush* brush); - - void transferMode(EngineMode newMode); void resetGLState(); - // fill, drawOutline, drawTexture & drawCachedGlyphs are the rendering entry points: + // fill, stroke, drawTexture, drawPixmaps & drawCachedGlyphs are the main rendering entry-points, + // however writeClip can also be thought of as en entry point as it does similar things. void fill(const QVectorPath &path); + void stroke(const QVectorPath &path, const QPen &pen); void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false); + void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints); void drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, const QTextItemInt &ti); + // draws whatever is in the vertex array: void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive); void drawVertexArrays(QGL2PEXVertexArray &vertexArray, GLenum primitive) { drawVertexArrays((const float *) vertexArray.data(), vertexArray.stops(), vertexArray.stopCount(), primitive); } - // ^ draws whatever is in the vertex array + // Composites the bounding rect onto dest buffer: void composite(const QGLRect& boundingRect); - // ^ Composites the bounding rect onto dest buffer + // Calls drawVertexArrays to render into stencil buffer: void fillStencilWithVertexArray(const float *data, int count, int *stops, int stopCount, const QGLRect &bounds, StencilFillMode mode); void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) { fillStencilWithVertexArray((const float *) vertexArray.data(), 0, vertexArray.stops(), vertexArray.stopCount(), vertexArray.boundingRect(), useWindingFill ? WindingFillMode : OddEvenFillMode); } - // ^ Calls drawVertexArrays to render into stencil buffer - - bool prepareForDraw(bool srcPixelsAreOpaque); - // ^ returns whether the current program changed or not + void setBrush(const QBrush& brush); + void transferMode(EngineMode newMode); + bool prepareForDraw(bool srcPixelsAreOpaque); // returns true if the program has changed inline void useSimpleShader(); + inline GLuint location(const QGLEngineShaderManager::Uniform uniform) { + return shaderManager->getUniformLocation(uniform); + } - void prepareDepthRangeForRenderText(); - void restoreDepthRangeForRenderText(); + void clearClip(uint value); + void writeClip(const QVectorPath &path, uint value); + void resetClipIfNeeded(); + + void updateClipScissorTest(); + void setScissor(const QRect &rect); + void regenerateClip(); + void systemStateChanged(); static QGLEngineShaderManager* shaderManagerForEngine(QGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; } static QGL2PaintEngineExPrivate *getData(QGL2PaintEngineEx *engine) { return engine->d_func(); } + static void cleanupVectorPath(QPaintEngineEx *engine, void *data); + QGL2PaintEngineEx* q; + QGLEngineShaderManager* shaderManager; QGLPaintDevice* device; int width, height; QGLContext *ctx; @@ -240,44 +253,28 @@ public: bool opacityUniformDirty; bool stencilClean; // Has the stencil not been used for clipping so far? + bool useSystemClip; QRegion dirtyStencilRegion; QRect currentScissorBounds; uint maxClip; - const QBrush* currentBrush; // May not be the state's brush! - - GLfloat inverseScale; + QBrush currentBrush; // May not be the state's brush! + const QBrush noBrush; QGL2PEXVertexArray vertexCoordinateArray; QGL2PEXVertexArray textureCoordinateArray; QDataBuffer<GLfloat> opacityArray; - GLfloat staticVertexCoordinateArray[8]; GLfloat staticTextureCoordinateArray[8]; - GLfloat pmvMatrix[4][4]; - - QGLEngineShaderManager* shaderManager; - - void clearClip(uint value); - void writeClip(const QVectorPath &path, uint value); - void resetClipIfNeeded(); - - void updateClipScissorTest(); - void setScissor(const QRect &rect); - void regenerateClip(); - void systemStateChanged(); - uint use_system_clip : 1; - - uint location(QGLEngineShaderManager::Uniform uniform) - { - return shaderManager->getUniformLocation(uniform); - } + bool snapToPixelGrid; + bool addOffset; // When enabled, adds a 0.49,0.49 offset to matrix in updateMatrix + GLfloat pmvMatrix[3][3]; + GLfloat inverseScale; - GLuint lastTexture; + GLuint lastTextureUsed; bool needsSync; - bool inRenderText; bool multisamplingAlwaysEnabled; GLfloat depthRange[2]; @@ -286,15 +283,11 @@ public: QTriangulatingStroker stroker; QDashedStrokeProcessor dasher; - QTransform temporaryTransform; QScopedPointer<QPixmapFilter> convolutionFilter; QScopedPointer<QPixmapFilter> colorizeFilter; QScopedPointer<QPixmapFilter> blurFilter; - QScopedPointer<QPixmapFilter> animationBlurFilter; - QScopedPointer<QPixmapFilter> fastBlurFilter; QScopedPointer<QPixmapFilter> dropShadowFilter; - QScopedPointer<QPixmapFilter> fastDropShadowFilter; QSet<QVectorPath::CacheEntry *> pathCaches; QVector<GLuint> unusedVBOSToClean; diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp new file mode 100644 index 0000000..047876f --- /dev/null +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtextureglyphcache_gl_p.h" +#include "qpaintengineex_opengl2_p.h" + +#ifdef Q_WS_WIN +extern Q_GUI_EXPORT bool qt_cleartype_enabled; +#endif + +QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix) + : QTextureGlyphCache(type, matrix) + , ctx(context) + , m_width(0) + , m_height(0) +{ + glGenFramebuffers(1, &m_fbo); + connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)), + SLOT(contextDestroyed(const QGLContext*))); +} + +QGLTextureGlyphCache::~QGLTextureGlyphCache() +{ + if (ctx) { + QGLShareContextScope scope(ctx); + glDeleteFramebuffers(1, &m_fbo); + + if (m_width || m_height) + glDeleteTextures(1, &m_texture); + } +} + +void QGLTextureGlyphCache::createTextureData(int width, int height) +{ + glGenTextures(1, &m_texture); + glBindTexture(GL_TEXTURE_2D, m_texture); + + m_width = width; + m_height = height; + + QVarLengthArray<uchar> data(width * height); + for (int i = 0; i < data.size(); ++i) + data[i] = 0; + + if (m_type == QFontEngineGlyphCache::Raster_RGBMask) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +} + +void QGLTextureGlyphCache::resizeTextureData(int width, int height) +{ + // ### the QTextureGlyphCache API needs to be reworked to allow + // ### resizeTextureData to fail + + int oldWidth = m_width; + int oldHeight = m_height; + + GLuint oldTexture = m_texture; + createTextureData(width, height); + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo); + + GLuint tmp_texture; + glGenTextures(1, &tmp_texture); + glBindTexture(GL_TEXTURE_2D, tmp_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, tmp_texture, 0); + + glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + glBindTexture(GL_TEXTURE_2D, oldTexture); + + pex->transferMode(BrushDrawingMode); + + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + + glViewport(0, 0, oldWidth, oldHeight); + + float vertexCoordinateArray[] = { -1, -1, 1, -1, 1, 1, -1, 1 }; + float textureCoordinateArray[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; + + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray); + glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray); + + pex->shaderManager->useBlitProgram(); + pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glBindTexture(GL_TEXTURE_2D, m_texture); + +#ifdef QT_OPENGL_ES_2 + QDataBuffer<uchar> buffer(4*oldWidth*oldHeight); + buffer.resize(4*oldWidth*oldHeight); + glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data()); + + // do an in-place conversion from GL_RGBA to GL_ALPHA + for (int i=0; i<oldWidth*oldHeight; ++i) + buffer.data()[i] = buffer.at(4*i + 3); + + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, + GL_ALPHA, GL_UNSIGNED_BYTE, buffer.data()); +#else + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); +#endif + + glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_RENDERBUFFER_EXT, 0); + glDeleteTextures(1, &tmp_texture); + glDeleteTextures(1, &oldTexture); + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); + + glViewport(0, 0, pex->width, pex->height); + pex->updateClipScissorTest(); +} + +void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) +{ + QImage mask = textureMapForGlyph(glyph); + const int maskWidth = mask.width(); + const int maskHeight = mask.height(); + + if (mask.format() == QImage::Format_Mono) { + mask = mask.convertToFormat(QImage::Format_Indexed8); + for (int y = 0; y < maskHeight; ++y) { + uchar *src = (uchar *) mask.scanLine(y); + for (int x = 0; x < maskWidth; ++x) + src[x] = -src[x]; // convert 0 and 1 into 0 and 255 + } + } + + + glBindTexture(GL_TEXTURE_2D, m_texture); + if (mask.format() == QImage::Format_RGB32) { + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits()); + } else { +#ifdef QT_OPENGL_ES2 + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits()); +#else + // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is + // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista + // and nVidia GeForce 8500GT. GL_UNPACK_ALIGNMENT is set to four bytes, 'mask' has a + // multiple of four bytes per line, and most of the glyph shows up correctly in the + // texture, which makes me think that this is a driver bug. + // One workaround is to make sure the mask width is a multiple of four bytes, for instance + // by converting it to a format with four bytes per pixel. Another is to copy one line at a + // time. + + for (int i = 0; i < maskHeight; ++i) + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i)); +#endif + } +} + +int QGLTextureGlyphCache::glyphMargin() const +{ +#if defined(Q_WS_MAC) + return 2; +#elif defined (Q_WS_X11) + return 0; +#else + return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0; +#endif +} diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h new file mode 100644 index 0000000..393893c --- /dev/null +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEXTUREGLYPHCACHE_GL_P_H +#define QTEXTUREGLYPHCACHE_GL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qtextureglyphcache_p.h> +#include <private/qgl_p.h> +#include <qglshaderprogram.h> + + +QT_BEGIN_NAMESPACE + +class QGL2PaintEngineExPrivate; + +class QGLTextureGlyphCache : public QObject, public QTextureGlyphCache +{ + Q_OBJECT +public: + QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix); + ~QGLTextureGlyphCache(); + + virtual void createTextureData(int width, int height); + virtual void resizeTextureData(int width, int height); + virtual void fillTexture(const Coord &c, glyph_t glyph); + virtual int glyphMargin() const; + + inline GLuint texture() const { return m_texture; } + + inline int width() const { return m_width; } + inline int height() const { return m_height; } + + inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; } + + +public Q_SLOTS: + void contextDestroyed(const QGLContext *context) { + if (context == ctx) { + const QGLContext *nextCtx = qt_gl_transfer_context(ctx); + if (!nextCtx) { + // the context may not be current, so we cannot directly + // destroy the fbo and texture here, but since the context + // is about to be destroyed, the GL server will do the + // clean up for us anyway + m_fbo = 0; + m_texture = 0; + ctx = 0; + } else { + // since the context holding the texture is shared, and + // about to be destroyed, we have to transfer ownership + // of the texture to one of the share contexts + ctx = const_cast<QGLContext *>(nextCtx); + } + } + } + +private: + QGLContext *ctx; + + QGL2PaintEngineExPrivate *pex; + + GLuint m_texture; + GLuint m_fbo; + + int m_width; + int m_height; + + QGLShaderProgram *m_program; +}; + +QT_END_NAMESPACE + +#endif + diff --git a/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp index 6082f49..395b8a3 100644 --- a/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp +++ b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp @@ -62,8 +62,14 @@ void QTriangulatingStroker::endCapOrJoinClosed(const qreal *start, const qreal * endCap(cur); } int count = m_vertices.size(); - m_vertices.add(m_vertices.at(count-2)); - m_vertices.add(m_vertices.at(count-1)); + + // Copy the (x, y) values because QDataBuffer::add(const float& t) + // may resize the buffer, which will leave t pointing at the + // previous buffer's memory region if we don't copy first. + float x = m_vertices.at(count-2); + float y = m_vertices.at(count-1); + m_vertices.add(x); + m_vertices.add(y); } diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index b2474ed..6076891 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -54,7 +54,8 @@ SOURCES += qgl.cpp \ gl2paintengineex/qpaintengineex_opengl2_p.h \ gl2paintengineex/qglengineshadersource_p.h \ gl2paintengineex/qglcustomshaderstage_p.h \ - gl2paintengineex/qtriangulatingstroker_p.h + gl2paintengineex/qtriangulatingstroker_p.h \ + gl2paintengineex/qtextureglyphcache_gl_p.h SOURCES += qglshaderprogram.cpp \ qglpixmapfilter.cpp \ @@ -67,7 +68,8 @@ SOURCES += qgl.cpp \ gl2paintengineex/qgl2pexvertexarray.cpp \ gl2paintengineex/qpaintengineex_opengl2.cpp \ gl2paintengineex/qglcustomshaderstage.cpp \ - gl2paintengineex/qtriangulatingstroker.cpp + gl2paintengineex/qtriangulatingstroker.cpp \ + gl2paintengineex/qtextureglyphcache_gl.cpp } diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 1bd1b91..c3e4a2e 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -397,8 +397,7 @@ static inline GLint qgluProject(GLdouble objx, GLdouble objy, GLdouble objz, \i \link setDirectRendering() Direct rendering:\endlink Enabled. \i \link setOverlay() Overlay:\endlink Disabled. \i \link setPlane() Plane:\endlink 0 (i.e., normal plane). - \i \link setSampleBuffers() Multisample buffers:\endlink Enabled on - OpenGL/ES 2.0, disabled on other platforms. + \i \link setSampleBuffers() Multisample buffers:\endlink Disabled. \endlist */ @@ -1437,6 +1436,18 @@ void QGLContextGroup::removeGuard(QGLSharedResourceGuard *guard) m_guards = guard->m_next; } +const QGLContext *qt_gl_transfer_context(const QGLContext *ctx) +{ + if (!ctx) + return 0; + QList<const QGLContext *> shares + (QGLContextPrivate::contextGroup(ctx)->shares()); + if (shares.size() >= 2) + return (ctx == shares.at(0)) ? shares.at(1) : shares.at(0); + else + return 0; +} + QGLContextPrivate::~QGLContextPrivate() { if (!group->m_refs.deref()) { @@ -1485,6 +1496,8 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format) current_fbo = 0; default_fbo = 0; active_engine = 0; + for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) + vertexAttributeArraysEnabledState[i] = false; } QGLContext* QGLContext::currentCtx = 0; @@ -1730,12 +1743,6 @@ struct DDSFormat { #define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192 #endif -Q_GLOBAL_STATIC(QGLShareRegister, _qgl_share_reg) -Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg() -{ - return _qgl_share_reg(); -} - /*! \class QGLContext \brief The QGLContext class encapsulates an OpenGL rendering context. @@ -1875,6 +1882,35 @@ void QGLContextPrivate::cleanup() { } +#define ctx q_ptr +void QGLContextPrivate::setVertexAttribArrayEnabled(int arrayIndex, bool enabled) +{ + Q_ASSERT(arrayIndex < QT_GL_VERTEX_ARRAY_TRACKED_COUNT); + Q_ASSERT(glEnableVertexAttribArray); + + if (vertexAttributeArraysEnabledState[arrayIndex] && !enabled) + glDisableVertexAttribArray(arrayIndex); + + if (!vertexAttributeArraysEnabledState[arrayIndex] && enabled) + glEnableVertexAttribArray(arrayIndex); + + vertexAttributeArraysEnabledState[arrayIndex] = enabled; +} + +void QGLContextPrivate::syncGlState() +{ + Q_ASSERT(glEnableVertexAttribArray); + for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) { + if (vertexAttributeArraysEnabledState[i]) + glEnableVertexAttribArray(i); + else + glDisableVertexAttribArray(i); + } + +} +#undef ctx + + /*! \overload @@ -2064,6 +2100,29 @@ QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G // #define QGL_BIND_TEXTURE_DEBUG +// map from Qt's ARGB endianness-dependent format to GL's big-endian RGBA layout +static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) +{ + const int width = img.width(); + const int height = img.height(); + + if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV + || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) + { + for (int i = 0; i < height; ++i) { + uint *p = (uint *) img.scanLine(i); + for (int x = 0; x < width; ++x) + p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); + } + } else { + for (int i = 0; i < height; ++i) { + uint *p = (uint *) img.scanLine(i); + for (int x = 0; x < width; ++x) + p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff); + } + } +} + QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint internalFormat, const qint64 key, QGLContext::BindOptions options) { @@ -2216,23 +2275,7 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G // 32 in the switch above is for the RGB16 case, where we set // the format to GL_RGB Q_ASSERT(img.depth() == 32); - const int width = img.width(); - const int height = img.height(); - - if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV - || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) { - for (int i=0; i < height; ++i) { - uint *p = (uint *) img.scanLine(i); - for (int x=0; x<width; ++x) - p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); - } - } else { - for (int i=0; i < height; ++i) { - uint *p = (uint *) img.scanLine(i); - for (int x=0; x<width; ++x) - p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff); - } - } + qgl_byteSwapImage(img, pixel_type); } #ifdef QT_OPENGL_ES // OpenGL/ES requires that the internal and external formats be identical. @@ -2948,7 +2991,7 @@ bool QGLContext::create(const QGLContext* shareContext) wd->usesDoubleBufferedGLContext = d->glFormat.doubleBuffer(); } if (d->sharing) // ok, we managed to share - qgl_share_reg()->addShare(this, shareContext); + QGLContextGroup::addShare(this, shareContext); return d->valid; } @@ -3804,6 +3847,11 @@ bool QGLWidget::event(QEvent *e) } #if defined(QT_OPENGL_ES) + // A re-parent is likely to destroy the X11 window and re-create it. It is important + // that we free the EGL surface _before_ the winID changes - otherwise we can leak. + if (e->type() == QEvent::ParentAboutToChange) + d->glcx->d_func()->destroyEglSurfaceForDevice(); + if ((e->type() == QEvent::ParentChange) || (e->type() == QEvent::WindowStateChange)) { // The window may have been re-created during re-parent or state change - if so, the EGL // surface will need to be re-created. @@ -4291,6 +4339,7 @@ static void qt_save_gl_state() glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } @@ -4344,6 +4393,10 @@ static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str, \note This function clears the stencil buffer. \note This function is not supported on OpenGL/ES systems. + + \note This function temporarily disables depth-testing when the + text is drawn. + \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead. */ @@ -4362,9 +4415,9 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, int height = d->glcx->device()->height(); bool auto_swap = autoBufferSwap(); + QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine(); + qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL); QPaintEngine *engine = paintEngine(); - if (engine->type() == QPaintEngine::OpenGL2) - static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true); QPainter *p; bool reuse_painter = false; if (engine->isActive()) { @@ -4384,11 +4437,6 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, setAutoBufferSwap(false); // disable glClear() as a result of QPainter::begin() d->disable_clear_on_painter_begin = true; - if (engine->type() == QPaintEngine::OpenGL2) { - qt_save_gl_state(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - } p = new QPainter(this); } @@ -4412,11 +4460,8 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, delete p; setAutoBufferSwap(auto_swap); d->disable_clear_on_painter_begin = false; - if (engine->type() == QPaintEngine::OpenGL2) - qt_restore_gl_state(); } - if (engine->type() == QPaintEngine::OpenGL2) - static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false); + qgl_engine_selector()->setPreferredPaintEngine(oldEngineType); #else // QT_OPENGL_ES Q_UNUSED(x); Q_UNUSED(y); @@ -4434,6 +4479,13 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, have the labels move with the model as it is rotated etc. \note This function is not supported on OpenGL/ES systems. + + \note If depth testing is enabled before this function is called, + then the drawn text will be depth-tested against the models that + have already been drawn in the scene. Use \c{glDisable(GL_DEPTH_TEST)} + before calling this function to annotate the models without + depth-testing the text. + \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead. */ void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font, int) @@ -4457,9 +4509,9 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con &win_x, &win_y, &win_z); win_y = height - win_y; // y is inverted + QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine(); + qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL); QPaintEngine *engine = paintEngine(); - if (engine->type() == QPaintEngine::OpenGL2) - static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true); QPainter *p; bool reuse_painter = false; bool use_depth_testing = glIsEnabled(GL_DEPTH_TEST); @@ -4473,8 +4525,6 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con setAutoBufferSwap(false); // disable glClear() as a result of QPainter::begin() d->disable_clear_on_painter_begin = true; - if (engine->type() == QPaintEngine::OpenGL2) - qt_save_gl_state(); p = new QPainter(this); } @@ -4503,13 +4553,10 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con } else { p->end(); delete p; - if (engine->type() == QPaintEngine::OpenGL2) - qt_restore_gl_state(); setAutoBufferSwap(auto_swap); d->disable_clear_on_painter_begin = false; } - if (engine->type() == QPaintEngine::OpenGL2) - static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false); + qgl_engine_selector()->setPreferredPaintEngine(oldEngineType); #else // QT_OPENGL_ES Q_UNUSED(x); Q_UNUSED(y); @@ -4823,38 +4870,39 @@ QGLWidget::QGLWidget(QGLContext *context, QWidget *parent, void QGLExtensions::init_extensions() { - QList<QByteArray> extensions = QByteArray(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))).split(' '); - if (extensions.contains("GL_ARB_texture_rectangle")) + QGLExtensionMatcher extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))); + + if (extensions.match("GL_ARB_texture_rectangle")) glExtensions |= TextureRectangle; - if (extensions.contains("GL_ARB_multisample")) + if (extensions.match("GL_ARB_multisample")) glExtensions |= SampleBuffers; - if (extensions.contains("GL_SGIS_generate_mipmap")) + if (extensions.match("GL_SGIS_generate_mipmap")) glExtensions |= GenerateMipmap; - if (extensions.contains("GL_ARB_texture_compression")) + if (extensions.match("GL_ARB_texture_compression")) glExtensions |= TextureCompression; - if (extensions.contains("GL_EXT_texture_compression_s3tc")) + if (extensions.match("GL_EXT_texture_compression_s3tc")) glExtensions |= DDSTextureCompression; - if (extensions.contains("GL_OES_compressed_ETC1_RGB8_texture")) + if (extensions.match("GL_OES_compressed_ETC1_RGB8_texture")) glExtensions |= ETC1TextureCompression; - if (extensions.contains("GL_IMG_texture_compression_pvrtc")) + if (extensions.match("GL_IMG_texture_compression_pvrtc")) glExtensions |= PVRTCTextureCompression; - if (extensions.contains("GL_ARB_fragment_program")) + if (extensions.match("GL_ARB_fragment_program")) glExtensions |= FragmentProgram; - if (extensions.contains("GL_ARB_fragment_shader")) + if (extensions.match("GL_ARB_fragment_shader")) glExtensions |= FragmentShader; - if (extensions.contains("GL_ARB_texture_mirrored_repeat")) + if (extensions.match("GL_ARB_texture_mirrored_repeat")) glExtensions |= MirroredRepeat; - if (extensions.contains("GL_EXT_framebuffer_object")) + if (extensions.match("GL_EXT_framebuffer_object")) glExtensions |= FramebufferObject; - if (extensions.contains("GL_EXT_stencil_two_side")) + if (extensions.match("GL_EXT_stencil_two_side")) glExtensions |= StencilTwoSide; - if (extensions.contains("GL_EXT_stencil_wrap")) + if (extensions.match("GL_EXT_stencil_wrap")) glExtensions |= StencilWrap; - if (extensions.contains("GL_EXT_packed_depth_stencil")) + if (extensions.match("GL_EXT_packed_depth_stencil")) glExtensions |= PackedDepthStencil; - if (extensions.contains("GL_NV_float_buffer")) + if (extensions.match("GL_NV_float_buffer")) glExtensions |= NVFloatBuffer; - if (extensions.contains("GL_ARB_pixel_buffer_object")) + if (extensions.match("GL_ARB_pixel_buffer_object")) glExtensions |= PixelBufferObject; #if defined(QT_OPENGL_ES_2) glExtensions |= FramebufferObject; @@ -4862,26 +4910,26 @@ void QGLExtensions::init_extensions() glExtensions |= FragmentShader; #endif #if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) - if (extensions.contains("GL_OES_framebuffer_object")) + if (extensions.match("GL_OES_framebuffer_object")) glExtensions |= FramebufferObject; #endif #if defined(QT_OPENGL_ES) - if (extensions.contains("GL_OES_packed_depth_stencil")) + if (extensions.match("GL_OES_packed_depth_stencil")) glExtensions |= PackedDepthStencil; #endif - if (extensions.contains("GL_ARB_framebuffer_object")) { + if (extensions.match("GL_ARB_framebuffer_object")) { // ARB_framebuffer_object also includes EXT_framebuffer_blit. glExtensions |= FramebufferObject; glExtensions |= FramebufferBlit; } - if (extensions.contains("GL_EXT_framebuffer_blit")) + if (extensions.match("GL_EXT_framebuffer_blit")) glExtensions |= FramebufferBlit; - if (extensions.contains("GL_ARB_texture_non_power_of_two")) + if (extensions.match("GL_ARB_texture_non_power_of_two")) glExtensions |= NPOTTextures; - if (extensions.contains("GL_EXT_bgra")) + if (extensions.match("GL_EXT_bgra")) glExtensions |= BGRATextureFormat; } @@ -4929,7 +4977,7 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name() } #endif -void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *share) { +void QGLContextGroup::addShare(const QGLContext *context, const QGLContext *share) { Q_ASSERT(context && share); if (context->d_ptr->group == share->d_ptr->group) return; @@ -4950,11 +4998,7 @@ void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *sha group->m_shares.append(context); } -QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) { - return context->d_ptr->group->m_shares; -} - -void QGLShareRegister::removeShare(const QGLContext *context) { +void QGLContextGroup::removeShare(const QGLContext *context) { // Remove the context from the group. QGLContextGroup *group = context->d_ptr->group; if (group->m_shares.isEmpty()) @@ -5363,11 +5407,12 @@ QSize QGLTexture::bindCompressedTexturePVR(const char *buf, int len) // Restore the default pixel alignment for later texture uploads. glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - // Set the invert flag for the texture. + // Set the invert flag for the texture. The "vertical flip" + // flag in PVR is the opposite sense to our sense of inversion. if ((pvrHeader->flags & PVR_VERTICAL_FLIP) != 0) - options |= QGLContext::InvertedYBindOption; - else options &= ~QGLContext::InvertedYBindOption; + else + options |= QGLContext::InvertedYBindOption; return QSize(pvrHeader->width, pvrHeader->height); } diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index 079953f..932ea7e 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -393,11 +393,12 @@ private: friend class QOpenGLPaintEnginePrivate; friend class QGL2PaintEngineEx; friend class QGL2PaintEngineExPrivate; + friend class QGLEngineShaderManager; friend class QGLWindowSurface; friend class QGLPixmapData; friend class QGLPixmapFilterBase; friend class QGLTextureGlyphCache; - friend class QGLShareRegister; + friend class QGLContextGroup; friend class QGLSharedResourceGuard; friend class QGLPixmapBlurFilter; friend QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags(); @@ -546,6 +547,7 @@ private: friend class QGLPixelBuffer; friend class QGLPixelBufferPrivate; friend class QGLContext; + friend class QGLContextPrivate; friend class QGLOverlayWidget; friend class QOpenGLPaintEngine; friend class QGLPaintDevice; diff --git a/src/opengl/qgl_egl.cpp b/src/opengl/qgl_egl.cpp index fbf0349..084db32 100644 --- a/src/opengl/qgl_egl.cpp +++ b/src/opengl/qgl_egl.cpp @@ -142,19 +142,7 @@ void QGLContext::reset() d->cleanup(); doneCurrent(); if (d->eglContext) { - if (d->eglSurface != EGL_NO_SURFACE) { -#ifdef Q_WS_X11 - // Make sure we don't call eglDestroySurface on a surface which - // was created for a different winId: - if (d->paintDevice->devType() == QInternal::Widget) { - QGLWidget* w = static_cast<QGLWidget*>(d->paintDevice); - - if (w->d_func()->eglSurfaceWindowId == w->winId()) - eglDestroySurface(d->eglContext->display(), d->eglSurface); - } else -#endif - eglDestroySurface(d->eglContext->display(), d->eglSurface); - } + d->destroyEglSurfaceForDevice(); delete d->eglContext; } d->eglContext = 0; @@ -164,7 +152,7 @@ void QGLContext::reset() d->valid = false; d->transpColor = QColor(); d->initDone = false; - qgl_share_reg()->removeShare(this); + QGLContextGroup::removeShare(this); } void QGLContext::makeCurrent() @@ -198,6 +186,26 @@ void QGLContext::swapBuffers() const d->eglContext->swapBuffers(d->eglSurface); } +void QGLContextPrivate::destroyEglSurfaceForDevice() +{ + if (eglSurface != EGL_NO_SURFACE) { +#ifdef Q_WS_X11 + // Make sure we don't call eglDestroySurface on a surface which + // was created for a different winId: + if (paintDevice->devType() == QInternal::Widget) { + QGLWidget* w = static_cast<QGLWidget*>(paintDevice); + + if (w->d_func()->eglSurfaceWindowId == w->winId()) + eglDestroySurface(eglContext->display(), eglSurface); + else + qWarning("WARNING: Potential EGL surface leak!"); + } else +#endif + eglDestroySurface(eglContext->display(), eglSurface); + eglSurface = EGL_NO_SURFACE; + } +} + void QGLWidget::setMouseTracking(bool enable) { QWidget::setMouseTracking(enable); diff --git a/src/opengl/qgl_mac.mm b/src/opengl/qgl_mac.mm index 4dd822d..8ecc48b 100644 --- a/src/opengl/qgl_mac.mm +++ b/src/opengl/qgl_mac.mm @@ -476,7 +476,7 @@ void QGLContext::reset() d->valid = false; d->transpColor = QColor(); d->initDone = false; - qgl_share_reg()->removeShare(this); + QGLContextGroup::removeShare(this); } void QGLContext::makeCurrent() diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 179d69a..fcfe791 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -133,9 +133,6 @@ public: : ref(1) { opts = QGL::DoubleBuffer | QGL::DepthBuffer | QGL::Rgba | QGL::DirectRendering | QGL::StencilBuffer; -#if defined(QT_OPENGL_ES_2) - opts |= QGL::SampleBuffers; -#endif pln = 0; depthSize = accumSize = stencilSize = redSize = greenSize = blueSize = alphaSize = -1; numSamples = -1; @@ -225,9 +222,8 @@ class QGLSharedResourceGuard; typedef QHash<QString, GLuint> QGLDDSCache; // QGLContextPrivate has the responsibility of creating context groups. -// QGLContextPrivate and QGLShareRegister will both maintain the reference counter and destroy +// QGLContextPrivate maintains the reference counter and destroys // context groups when needed. -// QGLShareRegister has the responsibility of keeping the context pointer up to date. class QGLContextGroup { public: @@ -236,9 +232,13 @@ public: QGLExtensionFuncs &extensionFuncs() {return m_extensionFuncs;} const QGLContext *context() const {return m_context;} bool isSharing() const { return m_shares.size() >= 2; } + QList<const QGLContext *> shares() const { return m_shares; } void addGuard(QGLSharedResourceGuard *guard); void removeGuard(QGLSharedResourceGuard *guard); + + static void addShare(const QGLContext *context, const QGLContext *share); + static void removeShare(const QGLContext *context); private: QGLContextGroup(const QGLContext *context) : m_context(context), m_guards(0), m_refs(1) { } @@ -252,14 +252,21 @@ private: void cleanupResources(const QGLContext *ctx); - friend class QGLShareRegister; friend class QGLContext; friend class QGLContextPrivate; friend class QGLContextResource; }; +// Get the context that resources for "ctx" will transfer to once +// "ctx" is destroyed. Returns null if nothing is sharing with ctx. +Q_OPENGL_EXPORT const QGLContext *qt_gl_transfer_context(const QGLContext *); + class QGLTexture; +// This probably needs to grow to GL_MAX_VERTEX_ATTRIBS, but 3 is ok for now as that's +// all the GL2 engine uses: +#define QT_GL_VERTEX_ARRAY_TRACKED_COUNT 3 + class QGLContextPrivate { Q_DECLARE_PUBLIC(QGLContext) @@ -279,6 +286,9 @@ public: void cleanup(); + void setVertexAttribArrayEnabled(int arrayIndex, bool enabled = true); + void syncGlState(); // Makes sure the GL context's state is what we think it is + #if defined(Q_WS_WIN) HGLRC rc; HDC dc; @@ -291,6 +301,7 @@ public: #if defined(QT_OPENGL_ES) QEglContext *eglContext; EGLSurface eglSurface; + void destroyEglSurfaceForDevice(); #elif defined(Q_WS_X11) || defined(Q_WS_MAC) void* cx; #endif @@ -334,6 +345,8 @@ public: GLuint default_fbo; QPaintEngine *active_engine; + bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT]; + static inline QGLContextGroup *contextGroup(const QGLContext *ctx) { return ctx->d_ptr->group; } #ifdef Q_WS_WIN @@ -397,19 +410,6 @@ public: Q_DECLARE_OPERATORS_FOR_FLAGS(QGLExtensions::Extensions) -class Q_AUTOTEST_EXPORT QGLShareRegister -{ -public: - QGLShareRegister() {} - ~QGLShareRegister() {} - - void addShare(const QGLContext *context, const QGLContext *share); - QList<const QGLContext *> shares(const QGLContext *context); - void removeShare(const QGLContext *context); -}; - -extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg(); - // Temporarily make a context current if not already current or // shared with the current contex. The previous context is made // current when the object goes out of scope. @@ -613,6 +613,49 @@ private: friend class QGLContextGroup; }; + +// This class can be used to match GL extensions with doing any mallocs. The +// class assumes that the GL extension string ends with a space character, +// which it should do on all conformant platforms. Create the object and pass +// in a pointer to the extension string, then call match() on each extension +// that should be matched. The match() function takes the extension name +// *without* the terminating space character as input. + +class QGLExtensionMatcher +{ +public: + QGLExtensionMatcher(const char *str) + : gl_extensions(str), gl_extensions_length(qstrlen(str)) + {} + + bool match(const char *str) { + int str_length = qstrlen(str); + const char *extensions = gl_extensions; + int extensions_length = gl_extensions_length; + + while (1) { + // the total length that needs to be matched is the str_length + + // the space character that terminates the extension name + if (extensions_length < str_length + 1) + return false; + if (qstrncmp(extensions, str, str_length) == 0 && extensions[str_length] == ' ') + return true; + + int split_pos = 0; + while (split_pos < extensions_length && extensions[split_pos] != ' ') + ++split_pos; + ++split_pos; // added for the terminating space character + extensions += split_pos; + extensions_length -= split_pos; + } + return false; + } + +private: + const char *gl_extensions; + int gl_extensions_length; +}; + QT_END_NAMESPACE #endif // QGL_P_H diff --git a/src/opengl/qgl_win.cpp b/src/opengl/qgl_win.cpp index 5b5820a..f80025d 100644 --- a/src/opengl/qgl_win.cpp +++ b/src/opengl/qgl_win.cpp @@ -1145,7 +1145,7 @@ void QGLContext::reset() delete d->cmap; d->cmap = 0; d->initDone = false; - qgl_share_reg()->removeShare(this); + QGLContextGroup::removeShare(this); } // diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index a037282..9fca28c 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -343,8 +343,8 @@ void* qglx_getProcAddress(const char* procName) static bool triedResolvingGlxGetProcAddress = false; if (!triedResolvingGlxGetProcAddress) { triedResolvingGlxGetProcAddress = true; - QList<QByteArray> glxExt = QByteArray(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)).split(' '); - if (glxExt.contains("GLX_ARB_get_proc_address")) { + QGLExtensionMatcher extensions(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)); + if (extensions.match("GLX_ARB_get_proc_address")) { #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) void *handle = dlopen(NULL, RTLD_LAZY); if (handle) { @@ -523,8 +523,8 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) if (!d->gpm) return false; } - QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(xinfo->display(), xinfo->screen())).split(' '); - if (glxExt.contains("GLX_SGI_video_sync")) { + QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen())); + if (extensions.match("GLX_SGI_video_sync")) { if (d->glFormat.swapInterval() == -1) d->glFormat.setSwapInterval(0); } else { @@ -630,8 +630,8 @@ void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth) static bool useTranspExt = false; static bool useTranspExtChecked = false; if (f.plane() && !useTranspExtChecked && d->paintDevice) { - QByteArray estr(glXQueryExtensionsString(xinfo->display(), xinfo->screen())); - useTranspExt = estr.contains("GLX_EXT_visual_info"); + QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen())); + useTranspExt = extensions.match("GLX_EXT_visual_info"); //# (A bit simplistic; that could theoretically be a substring) if (useTranspExt) { QByteArray cstr(glXGetClientString(xinfo->display(), GLX_VENDOR)); @@ -825,7 +825,7 @@ void QGLContext::reset() d->valid = false; d->transpColor = QColor(); d->initDone = false; - qgl_share_reg()->removeShare(this); + QGLContextGroup::removeShare(this); } @@ -875,8 +875,8 @@ void QGLContext::swapBuffers() const static bool resolved = false; if (!resolved) { const QX11Info *xinfo = qt_x11Info(d->paintDevice); - QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(xinfo->display(), xinfo->screen())).split(' '); - if (glxExt.contains("GLX_SGI_video_sync")) { + QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen())); + if (extensions.match("GLX_SGI_video_sync")) { glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI)qglx_getProcAddress("glXGetVideoSyncSGI"); glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI)qglx_getProcAddress("glXWaitVideoSyncSGI"); } @@ -1107,8 +1107,8 @@ void *QGLContext::getProcAddress(const QString &proc) const if (resolved && !glXGetProcAddressARB) return 0; if (!glXGetProcAddressARB) { - QList<QByteArray> glxExt = QByteArray(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)).split(' '); - if (glxExt.contains("GLX_ARB_get_proc_address")) { + QGLExtensionMatcher extensions(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)); + if (extensions.match("GLX_ARB_get_proc_address")) { #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) void *handle = dlopen(NULL, RTLD_LAZY); if (handle) { @@ -1132,6 +1132,72 @@ void *QGLContext::getProcAddress(const QString &proc) const return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(proc.toLatin1().data())); } +// +// This class is used to create a temporary, minimal GL context, which is used +// to retrive GL version and extension info. It's significantly faster to +// construct than a QGLWidget, and it doesn't have the recursive creation +// problem that QGLWidget would have. E.g. creating a temporary QGLWidget to +// retrieve GL info as part of the QGLWidget initialization. +// +class QGLTempContext +{ +public: + QGLTempContext(int screen = 0) : + initialized(false), + old_drawable(0), + old_context(0) + { + int attribs[] = {GLX_RGBA, XNone}; + XVisualInfo *vi = glXChooseVisual(X11->display, screen, attribs); + if (!vi) { + qWarning("QGLTempContext: No GL capable X visuals available."); + return; + } + + int useGL; + glXGetConfig(X11->display, vi, GLX_USE_GL, &useGL); + if (!useGL) { + XFree(vi); + return; + } + + old_drawable = glXGetCurrentDrawable(); + old_context = glXGetCurrentContext(); + + XSetWindowAttributes a; + a.colormap = qt_gl_choose_cmap(X11->display, vi); + drawable = XCreateWindow(X11->display, RootWindow(X11->display, screen), + 0, 0, 1, 1, 0, + vi->depth, InputOutput, vi->visual, + CWColormap, &a); + context = glXCreateContext(X11->display, vi, 0, True); + if (context && glXMakeCurrent(X11->display, drawable, context)) { + initialized = true; + } else { + qWarning("QGLTempContext: Unable to create GL context."); + XDestroyWindow(X11->display, drawable); + } + XFree(vi); + } + + ~QGLTempContext() { + if (initialized) { + glXMakeCurrent(X11->display, 0, 0); + glXDestroyContext(X11->display, context); + XDestroyWindow(X11->display, drawable); + } + if (old_drawable && old_context) + glXMakeCurrent(X11->display, old_drawable, old_context); + } + +private: + bool initialized; + Window drawable; + GLXContext context; + GLXDrawable old_drawable; + GLXContext old_context; +}; + /***************************************************************************** QGLOverlayWidget (Internal overlay class for X11) *****************************************************************************/ @@ -1574,8 +1640,7 @@ void QGLExtensions::init() return; init_done = true; - QGLWidget dmy; - dmy.makeCurrent(); + QGLTempContext context; init_extensions(); // nvidia 9x.xx unix drivers contain a bug which requires us to call glFinish before releasing an fbo @@ -1609,8 +1674,8 @@ static bool qt_resolveTextureFromPixmap(QPaintDevice *paintDevice) return false; // Can't use TFP without NPOT } const QX11Info *xinfo = qt_x11Info(paintDevice); - QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(xinfo->display(), xinfo->screen())).split(' '); - if (glxExt.contains("GLX_EXT_texture_from_pixmap")) { + QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen())); + if (extensions.match("GLX_EXT_texture_from_pixmap")) { glXBindTexImageEXT = (qt_glXBindTexImageEXT) qglx_getProcAddress("glXBindTexImageEXT"); glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) qglx_getProcAddress("glXReleaseTexImageEXT"); } diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index a868e83..271f4de 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -52,6 +52,116 @@ QT_BEGIN_NAMESPACE + +bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config, + const QX11Info &x11Info, bool useArgbVisual); +// +// QGLTempContext is a lass for creating a temporary GL context (which is +// needed during QGLWidget initialization to retrieve GL extension info). +// Faster to construct than a full QGLWidget. +// +class QGLTempContext +{ +public: + QGLTempContext(int screen = 0) : + initialized(false), + window(0), + context(0), + surface(0) + { + display = eglGetDisplay(EGLNativeDisplayType(X11->display)); + + if (!eglInitialize(display, NULL, NULL)) { + qWarning("QGLTempContext: Unable to initialize EGL display."); + return; + } + + EGLConfig config; + int numConfigs = 0; + EGLint attribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, +#ifdef QT_OPENGL_ES_2 + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, +#endif + EGL_NONE + }; + + eglChooseConfig(display, attribs, &config, 1, &numConfigs); + if (!numConfigs) { + qWarning("QGLTempContext: No EGL configurations available."); + return; + } + + XVisualInfo visualInfo; + XVisualInfo *vi; + int numVisuals; + EGLint id = 0; + + eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &id); + if (id == 0) { + // EGL_NATIVE_VISUAL_ID is optional and might not be supported + // on some implementations - we'll have to do it the hard way + QX11Info xinfo; + qt_egl_setup_x11_visual(visualInfo, display, config, xinfo, false); + } else { + visualInfo.visualid = id; + } + vi = XGetVisualInfo(X11->display, VisualIDMask, &visualInfo, &numVisuals); + if (!vi || numVisuals < 1) { + qWarning("QGLTempContext: Unable to get X11 visual info id."); + return; + } + + window = XCreateWindow(X11->display, RootWindow(X11->display, screen), + 0, 0, 1, 1, 0, + vi->depth, InputOutput, vi->visual, + 0, 0); + + surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType) window, NULL); + + if (surface == EGL_NO_SURFACE) { + qWarning("QGLTempContext: Error creating EGL surface."); + XFree(vi); + XDestroyWindow(X11->display, window); + return; + } + + EGLint contextAttribs[] = { +#ifdef QT_OPENGL_ES_2 + EGL_CONTEXT_CLIENT_VERSION, 2, +#endif + EGL_NONE + }; + context = eglCreateContext(display, config, 0, contextAttribs); + if (context != EGL_NO_CONTEXT + && eglMakeCurrent(display, surface, surface, context)) + { + initialized = true; + } else { + qWarning("QGLTempContext: Error creating EGL context."); + eglDestroySurface(display, surface); + XDestroyWindow(X11->display, window); + } + XFree(vi); + } + + ~QGLTempContext() { + if (initialized) { + eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(display, context); + eglDestroySurface(display, surface); + XDestroyWindow(X11->display, window); + } + } + +private: + bool initialized; + Window window; + EGLContext context; + EGLSurface surface; + EGLDisplay display; +}; + bool QGLFormat::hasOpenGLOverlays() { return false; @@ -173,10 +283,16 @@ void QGLWidget::updateOverlayGL() //handle overlay } +//#define QT_DEBUG_X11_VISUAL_SELECTION 1 + bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config, const QX11Info &x11Info, bool useArgbVisual) { bool foundVisualIsArgb = useArgbVisual; +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + qDebug("qt_egl_setup_x11_visual() - useArgbVisual=%d", useArgbVisual); +#endif + memset(&vi, 0, sizeof(XVisualInfo)); EGLint eglConfigColorSize; @@ -199,7 +315,9 @@ bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig conf XRenderPictFormat *format; format = XRenderFindVisualFormat(x11Info.display(), chosenVisualInfo->visual); if (format->type == PictTypeDirect && format->direct.alphaMask) { -// qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid); +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid); +#endif foundVisualIsArgb = true; vi = *chosenVisualInfo; } @@ -212,7 +330,9 @@ bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig conf #endif { if (eglConfigColorSize == chosenVisualInfo->depth) { -// qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid); +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid); +#endif vi = *chosenVisualInfo; } else qWarning("Warning: EGL suggested using X visual ID %d (%d bpp) for config %d (%d bpp), but the depths do not match!", @@ -248,7 +368,9 @@ bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig conf if (format->type == PictTypeDirect && format->direct.alphaMask) { vi = matchingVisuals[i]; foundVisualIsArgb = true; -// qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid); +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid); +#endif break; } } @@ -272,24 +394,28 @@ bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig conf } else qWarning(" - Falling back to X11 suggested depth (%d)", depth); } -// else -// qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth); +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + else + qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth); +#endif // Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-( if (useArgbVisual) foundVisualIsArgb = vi.depth == 32; //### We might at some point (soon) get ARGB4444 } -// qDebug("Visual Info:"); -// qDebug(" bits_per_rgb=%d", vi.bits_per_rgb); -// qDebug(" red_mask=0x%x", vi.red_mask); -// qDebug(" green_mask=0x%x", vi.green_mask); -// qDebug(" blue_mask=0x%x", vi.blue_mask); -// qDebug(" colormap_size=%d", vi.colormap_size); -// qDebug(" c_class=%d", vi.c_class); -// qDebug(" depth=%d", vi.depth); -// qDebug(" screen=%d", vi.screen); -// qDebug(" visualid=%d", vi.visualid); +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + qDebug("Visual Info:"); + qDebug(" bits_per_rgb=%d", vi.bits_per_rgb); + qDebug(" red_mask=0x%x", vi.red_mask); + qDebug(" green_mask=0x%x", vi.green_mask); + qDebug(" blue_mask=0x%x", vi.blue_mask); + qDebug(" colormap_size=%d", vi.colormap_size); + qDebug(" c_class=%d", vi.c_class); + qDebug(" depth=%d", vi.depth); + qDebug(" screen=%d", vi.screen); + qDebug(" visualid=%d", vi.visualid); +#endif return foundVisualIsArgb; } @@ -320,7 +446,7 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, // If the application has set WA_TranslucentBackground and not explicitly set // the alpha buffer size to zero, modify the format so it have an alpha channel QGLFormat& fmt = d->glcx->d_func()->glFormat; - const bool tryArgbVisual = testAttribute(Qt::WA_TranslucentBackground); + const bool tryArgbVisual = testAttribute(Qt::WA_TranslucentBackground) || fmt.alpha(); if (tryArgbVisual && fmt.alphaBufferSize() == -1) fmt.setAlphaBufferSize(1); @@ -430,12 +556,8 @@ void QGLExtensions::init() init_done = true; // We need a context current to initialize the extensions. - QGLWidget tmpWidget; - tmpWidget.makeCurrent(); - + QGLTempContext context; init_extensions(); - - tmpWidget.doneCurrent(); } // Re-creates the EGL surface if the window ID has changed or if force is true diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index d0297c9..4b5c30a 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -597,6 +597,12 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, the constructors that take a QGLFramebufferObject parameter, and set the QGLFramebufferObject::samples() property to a non-zero value. + When painting to a QGLFramebufferObject using QPainter, the state of + the current GL context will be altered by the paint engine to reflect + its needs. Applications should not rely upon the GL state being reset + to its original conditions, particularly the current shader program, + GL viewport, texture units, and drawing modes. + For multisample framebuffer objects a color render buffer is created, otherwise a texture with the specified texture target is created. The color render buffer or texture will have the specified internal diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index 7c97ebb..fab6efc 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -127,7 +127,7 @@ void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &form qctx = new QGLContext(format); qctx->d_func()->sharing = (shareWidget != 0); if (shareWidget != 0 && shareWidget->d_func()->glcx) { - qgl_share_reg()->addShare(qctx, shareWidget->d_func()->glcx); + QGLContextGroup::addShare(qctx, shareWidget->d_func()->glcx); shareWidget->d_func()->glcx->d_func()->sharing = true; } diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index c478630..d4bcbe9 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -55,11 +55,17 @@ #include "qgl_p.h" #include "private/qapplication_p.h" +#include "private/qdrawhelper_p.h" +#include "private/qmemrotate_p.h" #include "private/qmath_p.h" #include "qmath.h" QT_BEGIN_NAMESPACE +// qpixmapfilter.cpp +void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); +QImage qt_halfScaled(const QImage &source); + void QGLPixmapFilterBase::bindTexture(const QPixmap &src) const { const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, QGLContext::BindOptions(QGLContext::DefaultBindOption | QGLContext::MemoryManagedBindOption)); @@ -102,48 +108,21 @@ private: class QGLPixmapBlurFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapBlurFilter> { public: - QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHints hints); - - void setUniforms(QGLShaderProgram *program); - - static QByteArray generateGaussianShader(int radius, bool singlePass = false, bool dropShadow = false); + QGLPixmapBlurFilter(); protected: bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const; - -private: - - mutable QSize m_textureSize; - mutable bool m_horizontalBlur; - mutable bool m_singlePass; - mutable bool m_animatedBlur; - - mutable qreal m_t; - mutable QSize m_targetSize; - - mutable bool m_haveCached; - mutable int m_cachedRadius; - mutable QGraphicsBlurEffect::BlurHints m_hints; }; class QGLPixmapDropShadowFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapDropShadowFilter> { public: - QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHints hints); + QGLPixmapDropShadowFilter(); void setUniforms(QGLShaderProgram *program); protected: bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const; - -private: - mutable QSize m_textureSize; - mutable bool m_horizontalBlur; - mutable bool m_singlePass; - - mutable bool m_haveCached; - mutable int m_cachedRadius; - mutable QGraphicsBlurEffect::BlurHints m_hints; }; extern QGLWidget *qt_gl_share_widget(); @@ -158,31 +137,14 @@ QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *pr return d->colorizeFilter.data(); case QPixmapFilter::BlurFilter: { - const QPixmapBlurFilter *proto = static_cast<const QPixmapBlurFilter *>(prototype); - if (proto->blurHints() & QGraphicsBlurEffect::AnimationHint) { - if (!d->animationBlurFilter) - d->animationBlurFilter.reset(new QGLPixmapBlurFilter(proto->blurHints())); - return d->animationBlurFilter.data(); - } - if ((proto->blurHints() & QGraphicsBlurEffect::QualityHint) && proto->radius() > 5) { - if (!d->blurFilter) - d->blurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::QualityHint)); - return d->blurFilter.data(); - } - if (!d->fastBlurFilter) - d->fastBlurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::PerformanceHint)); - return d->fastBlurFilter.data(); + if (!d->blurFilter) + d->blurFilter.reset(new QGLPixmapBlurFilter()); + return d->blurFilter.data(); } case QPixmapFilter::DropShadowFilter: { - const QPixmapDropShadowFilter *proto = static_cast<const QPixmapDropShadowFilter *>(prototype); - if (proto->blurRadius() <= 5) { - if (!d->fastDropShadowFilter) - d->fastDropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::PerformanceHint)); - return d->fastDropShadowFilter.data(); - } if (!d->dropShadowFilter) - d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::QualityHint)); + d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter()); return d->dropShadowFilter.data(); } @@ -311,59 +273,43 @@ bool QGLPixmapConvolutionFilter::processGL(QPainter *painter, const QPointF &pos return true; } -static const char *qt_gl_texture_sampling_helper = - "lowp float texture2DAlpha(lowp sampler2D src, highp vec2 srcCoords) {\n" - " return texture2D(src, srcCoords).a;\n" - "}\n"; - -QGLPixmapBlurFilter::QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHints hints) - : m_animatedBlur(false) - , m_haveCached(false) - , m_cachedRadius(0) - , m_hints(hints) -{ -} - -// should be even numbers as they will be divided by two -static const int qCachedBlurLevels[] = { 6, 14, 30 }; -static const int qNumCachedBlurTextures = sizeof(qCachedBlurLevels) / sizeof(*qCachedBlurLevels); -static const int qMaxCachedBlurLevel = qCachedBlurLevels[qNumCachedBlurTextures - 1]; - -static qreal qLogBlurLevel(int level) +QGLPixmapBlurFilter::QGLPixmapBlurFilter() { - static bool initialized = false; - static qreal logBlurLevelCache[qNumCachedBlurTextures]; - if (!initialized) { - for (int i = 0; i < qNumCachedBlurTextures; ++i) - logBlurLevelCache[i] = qLn(qCachedBlurLevels[i]); - initialized = true; - } - return logBlurLevelCache[level]; } class QGLBlurTextureInfo { public: - QGLBlurTextureInfo(QSize size, GLuint textureIds[]) - : m_size(size) + QGLBlurTextureInfo(const QImage &image, GLuint tex, qreal r) + : m_texture(tex) + , m_radius(r) { - for (int i = 0; i < qNumCachedBlurTextures; ++i) - m_textureIds[i] = textureIds[i]; + m_paddedImage << image; } ~QGLBlurTextureInfo() { - glDeleteTextures(qNumCachedBlurTextures, m_textureIds); + glDeleteTextures(1, &m_texture); } - QSize size() const { return m_size; } - GLuint textureId(int i) const { return m_textureIds[i]; } + QImage paddedImage(int scaleLevel = 0) const; + GLuint texture() const { return m_texture; } + qreal radius() const { return m_radius; } private: - GLuint m_textureIds[qNumCachedBlurTextures]; - QSize m_size; + mutable QList<QImage> m_paddedImage; + GLuint m_texture; + qreal m_radius; }; +QImage QGLBlurTextureInfo::paddedImage(int scaleLevel) const +{ + for (int i = m_paddedImage.size() - 1; i <= scaleLevel; ++i) + m_paddedImage << qt_halfScaled(m_paddedImage.at(i)); + + return m_paddedImage.at(scaleLevel); +} + class QGLBlurTextureCache : public QObject { public: @@ -373,7 +319,6 @@ public: ~QGLBlurTextureCache(); QGLBlurTextureInfo *takeBlurTextureInfo(const QPixmap &pixmap); - bool fitsInCache(const QPixmap &pixmap) const; bool hasBlurTextureInfo(const QPixmap &pixmap) const; void insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info); void clearBlurTextureInfo(const QPixmap &pixmap); @@ -458,12 +403,7 @@ void QGLBlurTextureCache::insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTe if (timerId) killTimer(timerId); - timerId = startTimer(1000); -} - -bool QGLBlurTextureCache::fitsInCache(const QPixmap &pixmap) const -{ - return pixmap.width() * pixmap.height() <= cache.maxCost(); + timerId = startTimer(8000); } void QGLBlurTextureCache::pixmapDestroyed(QPixmap *pixmap) @@ -474,567 +414,217 @@ void QGLBlurTextureCache::pixmapDestroyed(QPixmap *pixmap) } } -static const char *qt_gl_interpolate_filter = - "uniform lowp float interpolationValue;" - "uniform lowp sampler2D interpolateTarget;" - "uniform highp vec4 interpolateMapping;" - "lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords)" - "{" - " return mix(texture2D(interpolateTarget, interpolateMapping.xy + interpolateMapping.zw * srcCoords)," - " texture2D(src, srcCoords), interpolationValue);" - "}"; +static const int qAnimatedBlurLevelIncrement = 16; +static const int qMaxBlurHalfScaleLevel = 1; -static void initializeTexture(GLuint id, int width, int height) +static GLuint generateBlurTexture(const QSize &size, GLenum format = GL_RGBA) { - glBindTexture(GL_TEXTURE_2D, id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glBindTexture(GL_TEXTURE_2D, 0); + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, + GL_UNSIGNED_BYTE, 0); + return texture; } -bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const +static inline uint nextMultiple(uint x, uint multiplier) { - QGLPixmapBlurFilter *filter = const_cast<QGLPixmapBlurFilter *>(this); - - QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); - QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx); - - if ((m_hints & QGraphicsBlurEffect::AnimationHint) && blurTextureCache->fitsInCache(src)) { - QRect targetRect = src.rect().adjusted(-qMaxCachedBlurLevel, -qMaxCachedBlurLevel, qMaxCachedBlurLevel, qMaxCachedBlurLevel); - // ensure even dimensions (going to divide by two) - targetRect.setWidth((targetRect.width() + 1) & ~1); - targetRect.setHeight((targetRect.height() + 1) & ~1); - - QGLBlurTextureInfo *info = 0; - if (blurTextureCache->hasBlurTextureInfo(src)) { - info = blurTextureCache->takeBlurTextureInfo(src); - } else { - m_animatedBlur = false; - m_hints = QGraphicsBlurEffect::QualityHint; - m_singlePass = false; - - QGLFramebufferObjectFormat format; - format.setInternalTextureFormat(GLenum(GL_RGBA)); - QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size() / 2, format, true); - - if (!fbo) - return false; - - QPainter fboPainter(fbo); - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(fboPainter.paintEngine()); - - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - // ensure GL_LINEAR filtering is used for scaling down to half the size - fboPainter.setRenderHint(QPainter::SmoothPixmapTransform); - fboPainter.setCompositionMode(QPainter::CompositionMode_Source); - fboPainter.drawPixmap(qMaxCachedBlurLevel / 2, qMaxCachedBlurLevel / 2, - targetRect.width() / 2 - qMaxCachedBlurLevel, targetRect.height() / 2 - qMaxCachedBlurLevel, src); - - GLuint textures[qNumCachedBlurTextures]; // blur textures - glGenTextures(qNumCachedBlurTextures, textures); - GLuint temp; // temp texture - glGenTextures(1, &temp); - - initializeTexture(temp, fbo->width(), fbo->height()); - m_textureSize = fbo->size(); - - int currentBlur = 0; - - QRect fboRect(0, 0, fbo->width(), fbo->height()); - GLuint sourceTexture = fbo->texture(); - for (int i = 0; i < qNumCachedBlurTextures; ++i) { - int targetBlur = qCachedBlurLevels[i] / 2; - - int blurDelta = qRound(qSqrt(targetBlur * targetBlur - currentBlur * currentBlur)); - QByteArray source = generateGaussianShader(blurDelta); - filter->setSource(source); - - currentBlur = targetBlur; - - // now we're going to be nasty and keep using the same FBO with different textures - glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, temp, 0); - - m_horizontalBlur = true; - filter->setOnPainter(&fboPainter); - engine->drawTexture(fboRect, sourceTexture, fbo->size(), fboRect); - filter->removeFromPainter(&fboPainter); - - sourceTexture = textures[i]; - initializeTexture(sourceTexture, fbo->width(), fbo->height()); - - glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, textures[i], 0); - - m_horizontalBlur = false; - filter->setOnPainter(&fboPainter); - engine->drawTexture(fboRect, temp, fbo->size(), fboRect); - filter->removeFromPainter(&fboPainter); - } - - glDeleteTextures(1, &temp); + uint mod = x % multiplier; + if (mod == 0) + return x; + return x + multiplier - mod; +} - // reattach the original FBO texture - glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, fbo->texture(), 0); +void qt_memrotate90_gl(const quint32 *src, int srcWidth, int srcHeight, int srcStride, + quint32 *dest, int dstStride); - fboPainter.end(); +bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const +{ + if (radius() < 1) { + painter->drawPixmap(pos, src); + return true; + } - qgl_fbo_pool()->release(fbo); + qreal actualRadius = radius(); - info = new QGLBlurTextureInfo(fboRect.size(), textures); - } + QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); - if (!m_haveCached || !m_animatedBlur) { - m_haveCached = true; - m_animatedBlur = true; - m_hints = QGraphicsBlurEffect::AnimationHint; - filter->setSource(qt_gl_interpolate_filter); - } + QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx); + QGLBlurTextureInfo *info = 0; + int padding = nextMultiple(qCeil(actualRadius), qAnimatedBlurLevelIncrement); + QRect targetRect = src.rect().adjusted(-padding, -padding, padding, padding); - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); + // pad so that we'll be able to half-scale qMaxBlurHalfScaleLevel times + targetRect.setWidth((targetRect.width() + (qMaxBlurHalfScaleLevel-1)) & ~(qMaxBlurHalfScaleLevel-1)); + targetRect.setHeight((targetRect.height() + (qMaxBlurHalfScaleLevel-1)) & ~(qMaxBlurHalfScaleLevel-1)); - qreal logRadius = qLn(radius()); + QSize textureSize; - int t; - for (t = -1; t < qNumCachedBlurTextures - 2; ++t) { - if (logRadius < qLogBlurLevel(t+1)) - break; - } + info = blurTextureCache->takeBlurTextureInfo(src); + if (!info || info->radius() < actualRadius) { + QSize paddedSize = targetRect.size() / 2; - qreal logBase = t >= 0 ? qLogBlurLevel(t) : 0; - m_t = qBound(qreal(0), (logRadius - logBase) / (qLogBlurLevel(t+1) - logBase), qreal(1)); + QImage padded(paddedSize.height(), paddedSize.width(), QImage::Format_ARGB32_Premultiplied); + padded.fill(0); - m_textureSize = info->size(); + if (info) { + int oldPadding = qRound(info->radius()); - glActiveTexture(GL_TEXTURE0 + 3); - if (t >= 0) { - glBindTexture(GL_TEXTURE_2D, info->textureId(t)); - m_targetSize = info->size(); + QPainter p(&padded); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.drawImage((padding - oldPadding) / 2, (padding - oldPadding) / 2, info->paddedImage()); + p.end(); } else { - QGLTexture *texture = - ctx->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, - QGLContext::InternalBindOption - | QGLContext::CanFlipNativePixmapBindOption); - m_targetSize = src.size(); - if (!(texture->options & QGLContext::InvertedYBindOption)) - m_targetSize.setHeight(-m_targetSize.height()); + // TODO: combine byteswapping and memrotating into one by declaring + // custom GL_RGBA pixel type and qt_colorConvert template for it + QImage prepadded = qt_halfScaled(src.toImage()).convertToFormat(QImage::Format_ARGB32_Premultiplied); + + // byte-swap and memrotates in one go + qt_memrotate90_gl(reinterpret_cast<const quint32*>(prepadded.bits()), + prepadded.width(), prepadded.height(), prepadded.bytesPerLine(), + reinterpret_cast<quint32*>(padded.scanLine(padding / 2)) + padding / 2, + padded.bytesPerLine()); } - // restrict the target rect to the max of the radii we are interpolating between - int radiusDelta = qMaxCachedBlurLevel - qCachedBlurLevels[t+1]; - targetRect = targetRect.translated(pos.toPoint()).adjusted(radiusDelta, radiusDelta, -radiusDelta, -radiusDelta); - - radiusDelta /= 2; - QRect sourceRect = QRect(QPoint(), m_textureSize).adjusted(radiusDelta, radiusDelta, -radiusDelta, -radiusDelta); - - engine->drawTexture(targetRect, info->textureId(t+1), m_textureSize, sourceRect); - - glActiveTexture(GL_TEXTURE0 + 3); - glBindTexture(GL_TEXTURE_2D, 0); - - filter->removeFromPainter(painter); - blurTextureCache->insertBlurTextureInfo(src, info); - - return true; - } + delete info; + info = new QGLBlurTextureInfo(padded, generateBlurTexture(paddedSize), padding); - if (blurTextureCache->hasBlurTextureInfo(src)) - blurTextureCache->clearBlurTextureInfo(src); - - int actualRadius = qRound(radius()); - int filterRadius = actualRadius; - int fastRadii[] = { 1, 2, 3, 5, 8, 15, 25 }; - if (!(m_hints & QGraphicsBlurEffect::QualityHint)) { - uint i = 0; - for (; i < (sizeof(fastRadii)/sizeof(*fastRadii))-1; ++i) { - if (fastRadii[i+1] > filterRadius) - break; - } - filterRadius = fastRadii[i]; + textureSize = paddedSize; + } else { + textureSize = QSize(info->paddedImage().height(), info->paddedImage().width()); } - m_singlePass = filterRadius <= 3; - - if (!m_haveCached || m_animatedBlur || filterRadius != m_cachedRadius) { - // Only regenerate the shader from source if parameters have changed. - m_haveCached = true; - m_animatedBlur = false; - m_cachedRadius = filterRadius; - QByteArray source = generateGaussianShader(filterRadius, m_singlePass); - filter->setSource(source); + actualRadius *= qreal(0.5); + int level = 1; + for (; level < qMaxBlurHalfScaleLevel; ++level) { + if (actualRadius <= 16) + break; + actualRadius *= qreal(0.5); } - QRect targetRect = QRectF(src.rect()).translated(pos).adjusted(-actualRadius, -actualRadius, actualRadius, actualRadius).toAlignedRect(); + const int s = (1 << level); - if (m_singlePass) { - // prepare for updateUniforms - m_textureSize = src.size(); + int prepadding = qRound(info->radius()); + padding = qMin(prepadding, qCeil(actualRadius) << level); + targetRect = src.rect().adjusted(-padding, -padding, padding, padding); - // ensure GL_LINEAR filtering is used - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); - QBrush pixmapBrush = src; - pixmapBrush.setTransform(QTransform::fromTranslate(pos.x(), pos.y())); - painter->fillRect(targetRect, pixmapBrush); - filter->removeFromPainter(painter); - } else { - QGLFramebufferObjectFormat format; - format.setInternalTextureFormat(GLenum(src.hasAlphaChannel() ? GL_RGBA : GL_RGB)); - QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size(), format); + targetRect.setWidth(targetRect.width() & ~(s-1)); + targetRect.setHeight(targetRect.height() & ~(s-1)); - if (!fbo) - return false; + int paddingDelta = (prepadding - padding) >> level; - // prepare for updateUniforms - m_textureSize = src.size(); + QRect subRect(paddingDelta, paddingDelta, targetRect.width() >> level, targetRect.height() >> level); + QImage sourceImage = info->paddedImage(level-1); - // horizontal pass, to pixmap - m_horizontalBlur = true; + QImage subImage(subRect.height(), subRect.width(), QImage::Format_ARGB32_Premultiplied); + qt_rectcopy((QRgb *)subImage.bits(), ((QRgb *)sourceImage.scanLine(paddingDelta)) + paddingDelta, + 0, 0, subRect.height(), subRect.width(), subImage.bytesPerLine(), sourceImage.bytesPerLine()); - QPainter fboPainter(fbo); + GLuint texture = info->texture(); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); + qt_blurImage(subImage, actualRadius, blurHints() & QGraphicsBlurEffect::QualityHint, 1); - // ensure GL_LINEAR filtering is used - fboPainter.setRenderHint(QPainter::SmoothPixmapTransform); - fboPainter.setCompositionMode(QPainter::CompositionMode_Source); - filter->setOnPainter(&fboPainter); - QBrush pixmapBrush = src; - pixmapBrush.setTransform(QTransform::fromTranslate(actualRadius, actualRadius)); - fboPainter.fillRect(QRect(0, 0, targetRect.width(), targetRect.height()), pixmapBrush); - filter->removeFromPainter(&fboPainter); - fboPainter.end(); + // subtract one pixel off the end to prevent the bilinear sampling from sampling uninitialized data + QRect textureSubRect = subImage.rect().adjusted(0, 0, -1, -1); + QRectF targetRectF = QRectF(targetRect).adjusted(0, 0, -targetRect.width() / qreal(textureSize.width()), -targetRect.height() / qreal(textureSize.height())); - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); + glBindTexture(GL_TEXTURE_2D, texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subImage.width(), subImage.height(), GL_RGBA, + GL_UNSIGNED_BYTE, const_cast<const QImage &>(subImage).bits()); - // vertical pass, to painter - m_horizontalBlur = false; - m_textureSize = fbo->size(); + QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); + painter->setRenderHint(QPainter::SmoothPixmapTransform); - painter->save(); - // ensure GL_LINEAR filtering is used - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); - engine->drawTexture(targetRect, fbo->texture(), fbo->size(), QRect(QPoint(), targetRect.size()).translated(0, fbo->height() - targetRect.height())); - filter->removeFromPainter(painter); - painter->restore(); + // texture is flipped on the y-axis + targetRectF = QRectF(targetRectF.x(), targetRectF.bottom(), targetRectF.width(), -targetRectF.height()); + engine->drawTexture(targetRectF.translated(pos), texture, textureSize, textureSubRect); - qgl_fbo_pool()->release(fbo); - } + blurTextureCache->insertBlurTextureInfo(src, info); return true; } -void QGLPixmapBlurFilter::setUniforms(QGLShaderProgram *program) -{ - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - if (m_animatedBlur) { - program->setUniformValue("interpolateTarget", 3); - program->setUniformValue("interpolationValue", GLfloat(m_t)); - - if (m_textureSize == m_targetSize) { - program->setUniformValue("interpolateMapping", 0.0f, 0.0f, 1.0f, 1.0f); - } else { - float offsetX = (-qMaxCachedBlurLevel - 0.5) / qreal(m_targetSize.width()); - float offsetY = (-qMaxCachedBlurLevel - 0.5) / qreal(m_targetSize.height()); - - if (m_targetSize.height() < 0) - offsetY = 1 + offsetY; - - float scaleX = 2.0f * qreal(m_textureSize.width()) / qreal(m_targetSize.width()); - float scaleY = 2.0f * qreal(m_textureSize.height()) / qreal(m_targetSize.height()); - - program->setUniformValue("interpolateMapping", offsetX, offsetY, scaleX, scaleY); - } - - return; - } +static const char *qt_gl_drop_shadow_filter = + "uniform lowp vec4 shadowColor;" + "lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords)" + "{" + " return shadowColor * texture2D(src, srcCoords.yx).a;" + "}"; - if (m_hints & QGraphicsBlurEffect::QualityHint) { - if (m_singlePass) - program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height()); - else if (m_horizontalBlur) - program->setUniformValue("delta", 1.0 / m_textureSize.width(), 0.0); - else - program->setUniformValue("delta", 0.0, 1.0 / m_textureSize.height()); - } else { - qreal blur = radius() / qreal(m_cachedRadius); - - if (m_singlePass) - program->setUniformValue("delta", blur / m_textureSize.width(), blur / m_textureSize.height()); - else if (m_horizontalBlur) - program->setUniformValue("delta", blur / m_textureSize.width(), 0.0); - else - program->setUniformValue("delta", 0.0, blur / m_textureSize.height()); - } -} -static inline qreal gaussian(qreal dx, qreal sigma) +QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter() { - return exp(-dx * dx / (2 * sigma * sigma)) / (Q_2PI * sigma * sigma); + setSource(qt_gl_drop_shadow_filter); } -QByteArray QGLPixmapBlurFilter::generateGaussianShader(int radius, bool singlePass, bool dropShadow) +bool QGLPixmapDropShadowFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const { - Q_ASSERT(radius >= 1); - - radius = qMin(127, radius); - - static QCache<uint, QByteArray> shaderSourceCache; - uint key = radius | (int(singlePass) << 7) | (int(dropShadow) << 8); - QByteArray *cached = shaderSourceCache.object(key); - if (cached) - return *cached; - - QByteArray source; - source.reserve(1000); - source.append(qt_gl_texture_sampling_helper); - - source.append("uniform highp vec2 delta;\n"); - if (dropShadow) - source.append("uniform mediump vec4 shadowColor;\n"); - source.append("lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords) {\n"); - - QVector<qreal> sampleOffsets; - QVector<qreal> weights; - - QVector<qreal> gaussianComponents; - - qreal sigma = radius / 1.65; - - qreal sum = 0; - for (int i = -radius; i < radius; ++i) { - float value = gaussian(i, sigma); - gaussianComponents << value; - sum += value; - } - - // normalize - for (int i = 0; i < gaussianComponents.size(); ++i) - gaussianComponents[i] /= sum; - - for (int i = 0; i < gaussianComponents.size() - 1; i += 2) { - qreal weight = gaussianComponents.at(i) + gaussianComponents.at(i + 1); - qreal offset = i - radius + gaussianComponents.at(i + 1) / weight; - - sampleOffsets << offset; - weights << weight; - } - - int limit = sampleOffsets.size(); - if (singlePass) - limit *= limit; - - QByteArray baseCoordinate = "srcCoords"; - - for (int i = 0; i < limit; ++i) { - QByteArray coordinate = baseCoordinate; - - qreal weight; - if (singlePass) { - const int xIndex = i % sampleOffsets.size(); - const int yIndex = i / sampleOffsets.size(); - - const qreal deltaX = sampleOffsets.at(xIndex); - const qreal deltaY = sampleOffsets.at(yIndex); - weight = weights.at(xIndex) * weights.at(yIndex); - - if (!qFuzzyCompare(deltaX, deltaY)) { - coordinate.append(" + vec2(delta.x * float("); - coordinate.append(QByteArray::number(deltaX)); - coordinate.append("), delta.y * float("); - coordinate.append(QByteArray::number(deltaY)); - coordinate.append("))"); - } else if (!qFuzzyIsNull(deltaX)) { - coordinate.append(" + delta * float("); - coordinate.append(QByteArray::number(deltaX)); - coordinate.append(")"); - } - } else { - const qreal delta = sampleOffsets.at(i); - weight = weights.at(i); - if (!qFuzzyIsNull(delta)) { - coordinate.append(" + delta * float("); - coordinate.append(QByteArray::number(delta)); - coordinate.append(")"); - } - } - - if (i == 0) { - if (dropShadow) - source.append(" mediump float sample = "); - else - source.append(" mediump vec4 sample = "); - } else { - if (dropShadow) - source.append(" sample += "); - else - source.append(" sample += "); - } + QGLPixmapDropShadowFilter *filter = const_cast<QGLPixmapDropShadowFilter *>(this); - source.append("texture2D(src, "); - source.append(coordinate); - source.append(")"); + qreal r = blurRadius(); + QRectF targetRectUnaligned = QRectF(src.rect()).translated(pos + offset()).adjusted(-r, -r, r, r); + QRect targetRect = targetRectUnaligned.toAlignedRect(); - if (dropShadow) - source.append(".a"); + // ensure even dimensions (going to divide by two) + targetRect.setWidth((targetRect.width() + 1) & ~1); + targetRect.setHeight((targetRect.height() + 1) & ~1); - if (!qFuzzyCompare(weight, qreal(1))) { - source.append(" * float("); - source.append(QByteArray::number(weight)); - source.append(");\n"); - } else { - source.append(";\n"); - } - } + QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); + QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx); - source.append(" return "); - if (dropShadow) - source.append("shadowColor * "); - source.append("sample;\n"); - source.append("}\n"); + QGLBlurTextureInfo *info = blurTextureCache->takeBlurTextureInfo(src); + if (!info || info->radius() != r) { + QImage half = qt_halfScaled(src.toImage().alphaChannel()); - cached = new QByteArray(source); - shaderSourceCache.insert(key, cached); + qreal rx = r + targetRect.left() - targetRectUnaligned.left(); + qreal ry = r + targetRect.top() - targetRectUnaligned.top(); - return source; -} + QImage image = QImage(targetRect.size() / 2, QImage::Format_Indexed8); + image.setColorTable(half.colorTable()); + image.fill(0); + int dx = qRound(rx * qreal(0.5)); + int dy = qRound(ry * qreal(0.5)); + qt_rectcopy(image.bits(), half.bits(), dx, dy, + half.width(), half.height(), + image.bytesPerLine(), half.bytesPerLine()); -QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHints hints) - : m_haveCached(false) - , m_cachedRadius(0) - , m_hints(hints) -{ -} + qt_blurImage(image, r * qreal(0.5), false, 1); -bool QGLPixmapDropShadowFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const -{ - QGLPixmapDropShadowFilter *filter = const_cast<QGLPixmapDropShadowFilter *>(this); + GLuint texture = generateBlurTexture(image.size(), GL_ALPHA); - int actualRadius = qRound(blurRadius()); - int filterRadius = actualRadius; - m_singlePass = filterRadius <= 3; + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image.width(), image.height(), GL_ALPHA, + GL_UNSIGNED_BYTE, image.bits()); - if (!m_haveCached || filterRadius != m_cachedRadius) { - // Only regenerate the shader from source if parameters have changed. - m_haveCached = true; - m_cachedRadius = filterRadius; - QByteArray source = QGLPixmapBlurFilter::generateGaussianShader(filterRadius, m_singlePass, true); - filter->setSource(source); + info = new QGLBlurTextureInfo(image, texture, r); } - QRect targetRect = QRectF(src.rect()).translated(pos + offset()).adjusted(-actualRadius, -actualRadius, actualRadius, actualRadius).toAlignedRect(); - - if (m_singlePass) { - // prepare for updateUniforms - m_textureSize = src.size(); - - painter->save(); - // ensure GL_LINEAR filtering is used - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); - QBrush pixmapBrush = src; - pixmapBrush.setTransform(QTransform::fromTranslate(pos.x() + offset().x(), pos.y() + offset().y())); - painter->fillRect(targetRect, pixmapBrush); - filter->removeFromPainter(painter); - painter->restore(); - } else { - QGLFramebufferObjectFormat format; - format.setInternalTextureFormat(GLenum(src.hasAlphaChannel() ? GL_RGBA : GL_RGB)); - QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size(), format); - - if (!fbo) - return false; - - // prepare for updateUniforms - m_textureSize = src.size(); - - // horizontal pass, to pixmap - m_horizontalBlur = true; - - QPainter fboPainter(fbo); + GLuint texture = info->texture(); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - // ensure GL_LINEAR filtering is used - fboPainter.setRenderHint(QPainter::SmoothPixmapTransform); - fboPainter.setCompositionMode(QPainter::CompositionMode_Source); - filter->setOnPainter(&fboPainter); - QBrush pixmapBrush = src; - pixmapBrush.setTransform(QTransform::fromTranslate(actualRadius, actualRadius)); - fboPainter.fillRect(QRect(0, 0, targetRect.width(), targetRect.height()), pixmapBrush); - filter->removeFromPainter(&fboPainter); - fboPainter.end(); - - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); + filter->setOnPainter(painter); - // vertical pass, to painter - m_horizontalBlur = false; - m_textureSize = fbo->size(); + QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); + painter->setRenderHint(QPainter::SmoothPixmapTransform); - painter->save(); - // ensure GL_LINEAR filtering is used - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); - engine->drawTexture(targetRect, fbo->texture(), fbo->size(), QRectF(0, fbo->height() - targetRect.height(), targetRect.width(), targetRect.height())); - filter->removeFromPainter(painter); - painter->restore(); + engine->drawTexture(targetRect, texture, info->paddedImage().size(), info->paddedImage().rect()); - qgl_fbo_pool()->release(fbo); - } + filter->removeFromPainter(painter); // Now draw the actual pixmap over the top. painter->drawPixmap(pos, src, srcRect); + blurTextureCache->insertBlurTextureInfo(src, info); + return true; } void QGLPixmapDropShadowFilter::setUniforms(QGLShaderProgram *program) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - QColor col = color(); - if (m_horizontalBlur && !m_singlePass) { - program->setUniformValue("shadowColor", 1.0f, 1.0f, 1.0f, 1.0f); - } else { - qreal alpha = col.alphaF(); - program->setUniformValue("shadowColor", col.redF() * alpha, - col.greenF() * alpha, - col.blueF() * alpha, - alpha); - } - - if (m_hints & QGraphicsBlurEffect::QualityHint) { - if (m_singlePass) - program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height()); - else if (m_horizontalBlur) - program->setUniformValue("delta", 1.0 / m_textureSize.width(), 0.0); - else - program->setUniformValue("delta", 0.0, 1.0 / m_textureSize.height()); - } else { - qreal blur = blurRadius() / qreal(m_cachedRadius); - - if (m_singlePass) - program->setUniformValue("delta", blur / m_textureSize.width(), blur / m_textureSize.height()); - else if (m_horizontalBlur) - program->setUniformValue("delta", blur / m_textureSize.width(), 0.0); - else - program->setUniformValue("delta", 0.0, blur / m_textureSize.height()); - } + qreal alpha = col.alphaF(); + program->setUniformValue("shadowColor", col.redF() * alpha, + col.greenF() * alpha, + col.blueF() * alpha, + alpha); } QT_END_NAMESPACE diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index ed7fdff..8dae02a 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -4522,6 +4522,12 @@ typedef QHash<QFontEngine*, QGLGlyphHash*> QGLFontGlyphHash; typedef QHash<quint64, QGLFontTexture*> QGLFontTexHash; typedef QHash<const QGLContext*, QGLFontGlyphHash*> QGLContextHash; +static inline void qt_delete_glyph_hash(QGLGlyphHash *hash) +{ + qDeleteAll(*hash); + delete hash; +} + class QGLGlyphCache : public QObject { Q_OBJECT @@ -4562,7 +4568,7 @@ void QGLGlyphCache::fontEngineDestroyed(QObject *o) if (font_cache->find(fe) != font_cache->end()) { ctx = keys.at(i); QGLGlyphHash *cache = font_cache->take(fe); - delete cache; + qt_delete_glyph_hash(cache); break; } } @@ -4599,7 +4605,7 @@ void QGLGlyphCache::cleanupContext(const QGLContext *ctx) QList<QFontEngine *> keys = font_cache->keys(); for (int i=0; i < keys.size(); ++i) { QFontEngine *fe = keys.at(i); - delete font_cache->take(fe); + qt_delete_glyph_hash(font_cache->take(fe)); quint64 font_key = (reinterpret_cast<quint64>(ctx) << 32) | reinterpret_cast<quint64>(fe); QGLFontTexture *font_tex = qt_font_textures.take(font_key); if (font_tex) { @@ -4640,7 +4646,9 @@ void QGLGlyphCache::cleanCache() QList<const QGLContext *> keys = qt_context_cache.keys(); for (int i=0; i < keys.size(); ++i) { QGLFontGlyphHash *font_cache = qt_context_cache.value(keys.at(i)); - qDeleteAll(*font_cache); + QGLFontGlyphHash::Iterator it = font_cache->begin(); + for (; it != font_cache->end(); ++it) + qt_delete_glyph_hash(it.value()); font_cache->clear(); } qDeleteAll(qt_context_cache); diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index 0299cea..92c990b 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -341,22 +341,11 @@ void QGLPixmapData::ensureCreated() const if (!m_source.isNull()) { if (external_format == GL_RGB) { - QImage tx = m_source.convertToFormat(QImage::Format_RGB32); - - QVector<uchar> pixelData(w * h * 3); - uchar *p = &pixelData[0]; - QRgb *src = (QRgb *)tx.bits(); - - for (int i = 0; i < w * h; ++i) { - *p++ = qRed(*src); - *p++ = qGreen(*src); - *p++ = qBlue(*src); - ++src; - } + const QImage tx = m_source.convertToFormat(QImage::Format_RGB888); glBindTexture(target, m_texture.id); glTexSubImage2D(target, 0, 0, 0, w, h, external_format, - GL_UNSIGNED_BYTE, &pixelData[0]); + GL_UNSIGNED_BYTE, tx.bits()); } else { const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, external_format); @@ -424,6 +413,7 @@ bool QGLPixmapData::fromFile(const QString &filename, const char *format, resize(0, 0); data = file.readAll(); file.close(); + QGLShareContextScope ctx(qt_gl_share_widget()->context()); QSize size = m_texture.bindCompressedTexture (data.constData(), data.size(), format); if (!size.isEmpty()) { @@ -449,6 +439,7 @@ bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format, const char *buf = reinterpret_cast<const char *>(buffer); if (m_texture.canBindCompressedTexture(buf, int(len), format, &alpha)) { resize(0, 0); + QGLShareContextScope ctx(qt_gl_share_widget()->context()); QSize size = m_texture.bindCompressedTexture(buf, int(len), format); if (!size.isEmpty()) { w = size.width(); diff --git a/src/openvg/openvg.pro b/src/openvg/openvg.pro index 8927c4c..c8c9917 100644 --- a/src/openvg/openvg.pro +++ b/src/openvg/openvg.pro @@ -16,11 +16,13 @@ HEADERS += \ qpaintengine_vg_p.h \ qpixmapdata_vg_p.h \ qpixmapfilter_vg_p.h \ - qvgcompositionhelper_p.h + qvgcompositionhelper_p.h \ + qvgimagepool_p.h SOURCES += \ qpaintengine_vg.cpp \ qpixmapdata_vg.cpp \ - qpixmapfilter_vg.cpp + qpixmapfilter_vg.cpp \ + qvgimagepool.cpp contains(QT_CONFIG, egl) { HEADERS += \ diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index 6b829dd..117c910 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -43,6 +43,7 @@ #include "qpixmapdata_vg_p.h" #include "qpixmapfilter_vg_p.h" #include "qvgcompositionhelper_p.h" +#include "qvgimagepool_p.h" #if !defined(QT_NO_EGL) #include <QtGui/private/qegl_p.h> #include "qwindowsurface_vgegl_p.h" @@ -199,6 +200,7 @@ public: QRegion scissorRegion; // Currently active scissor region. bool scissorActive; // True if scissor region is active. + bool scissorDirty; // True if scissor is dirty after native painting. QPaintEngine::DirtyFlags dirty; @@ -356,6 +358,7 @@ void QVGPaintEnginePrivate::init() rawVG = false; scissorActive = false; + scissorDirty = false; dirty = 0; @@ -983,6 +986,9 @@ static QImage colorizeBitmap(const QImage &image, const QColor &color) return dest; } +// defined in qpixmapdata_vg.cpp. +const uchar *qt_vg_imageBits(const QImage& image); + static VGImage toVGImage (const QImage & image, Qt::ImageConversionFlags flags = Qt::AutoColor) { @@ -1016,9 +1022,9 @@ static VGImage toVGImage break; } - const uchar *pixels = img.bits(); + const uchar *pixels = qt_vg_imageBits(img); - VGImage vgImg = vgCreateImage + VGImage vgImg = QVGImagePool::instance()->createPermanentImage (format, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); vgImageSubData (vgImg, pixels, img.bytesPerLine(), format, 0, 0, @@ -1060,10 +1066,10 @@ static VGImage toVGImageSubRect break; } - const uchar *pixels = img.bits() + bpp * sr.x() + + const uchar *pixels = qt_vg_imageBits(img) + bpp * sr.x() + img.bytesPerLine() * sr.y(); - VGImage vgImg = vgCreateImage + VGImage vgImg = QVGImagePool::instance()->createPermanentImage (format, sr.width(), sr.height(), VG_IMAGE_QUALITY_FASTER); vgImageSubData (vgImg, pixels, img.bytesPerLine(), format, 0, 0, @@ -1082,9 +1088,9 @@ static VGImage toVGImageWithOpacity(const QImage & image, qreal opacity) painter.drawImage(0, 0, image); painter.end(); - const uchar *pixels = img.bits(); + const uchar *pixels = qt_vg_imageBits(img); - VGImage vgImg = vgCreateImage + VGImage vgImg = QVGImagePool::instance()->createPermanentImage (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); vgImageSubData (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, @@ -1104,9 +1110,9 @@ static VGImage toVGImageWithOpacitySubRect painter.drawImage(QPoint(0, 0), image, sr); painter.end(); - const uchar *pixels = img.bits(); + const uchar *pixels = qt_vg_imageBits(img); - VGImage vgImg = vgCreateImage + VGImage vgImg = QVGImagePool::instance()->createPermanentImage (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); vgImageSubData (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, @@ -1194,6 +1200,12 @@ VGPaintType QVGPaintEnginePrivate::setBrush if (pd->classId() == QPixmapData::OpenVGClass) { QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd); vgImg = vgpd->toVGImage(); + + // We don't want the pool to reclaim this image + // because we cannot predict when the paint object + // will stop using it. Replacing the image with + // new data will make the paint object invalid. + vgpd->detachImageFromPool(); } else { vgImg = toVGImage(*(pd->buffer())); deref = true; @@ -1201,6 +1213,7 @@ VGPaintType QVGPaintEnginePrivate::setBrush } else if (pd->classId() == QPixmapData::OpenVGClass) { QVGPixmapData *vgpd = static_cast<QVGPixmapData *>(pd); vgImg = vgpd->toVGImage(opacity); + vgpd->detachImageFromPool(); } else { vgImg = toVGImageWithOpacity(*(pd->buffer()), opacity); deref = true; @@ -2075,6 +2088,7 @@ void QVGPaintEngine::updateScissor() // so there is no point doing any scissoring. vgSeti(VG_SCISSORING, VG_FALSE); d->scissorActive = false; + d->scissorDirty = false; return; } } else @@ -2092,6 +2106,7 @@ void QVGPaintEngine::updateScissor() // so there is no point doing any scissoring. vgSeti(VG_SCISSORING, VG_FALSE); d->scissorActive = false; + d->scissorDirty = false; return; } } else @@ -2101,11 +2116,12 @@ void QVGPaintEngine::updateScissor() if (region.isEmpty()) { vgSeti(VG_SCISSORING, VG_FALSE); d->scissorActive = false; + d->scissorDirty = false; return; } } - if (d->scissorActive && region == d->scissorRegion) + if (d->scissorActive && region == d->scissorRegion && !d->scissorDirty) return; QVector<QRect> rects = region.rects(); @@ -2123,6 +2139,7 @@ void QVGPaintEngine::updateScissor() vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data()); vgSeti(VG_SCISSORING, VG_TRUE); + d->scissorDirty = false; d->scissorActive = true; d->scissorRegion = region; } @@ -3158,15 +3175,15 @@ void QVGFontGlyphCache::cacheGlyphs if (!scaledImage.isNull()) { // Not a space character if (scaledImage.format() == QImage::Format_Indexed8) { vgImage = vgCreateImage(VG_A_8, scaledImage.width(), scaledImage.height(), VG_IMAGE_QUALITY_FASTER); - vgImageSubData(vgImage, scaledImage.bits(), scaledImage.bytesPerLine(), VG_A_8, 0, 0, scaledImage.width(), scaledImage.height()); + vgImageSubData(vgImage, qt_vg_imageBits(scaledImage), scaledImage.bytesPerLine(), VG_A_8, 0, 0, scaledImage.width(), scaledImage.height()); } else if (scaledImage.format() == QImage::Format_Mono) { QImage img = scaledImage.convertToFormat(QImage::Format_Indexed8); vgImage = vgCreateImage(VG_A_8, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); - vgImageSubData(vgImage, img.bits(), img.bytesPerLine(), VG_A_8, 0, 0, img.width(), img.height()); + vgImageSubData(vgImage, qt_vg_imageBits(img), img.bytesPerLine(), VG_A_8, 0, 0, img.width(), img.height()); } else { QImage img = scaledImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); vgImage = vgCreateImage(VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); - vgImageSubData(vgImage, img.bits(), img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height()); + vgImageSubData(vgImage, qt_vg_imageBits(img), img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height()); } } origin[0] = -metrics.x.toReal() + 0.5f; @@ -3325,6 +3342,7 @@ void QVGPaintEngine::endNativePainting() d->brushType = (VGPaintType)0; d->clearColor = QColor(); d->fillPaint = d->brushPaint; + d->scissorDirty = true; restoreState(QPaintEngine::AllDirty); d->dirty = dirty; d->rawVG = false; @@ -3632,7 +3650,7 @@ void QVGCompositionHelper::drawCursorPixmap if (vgImage == VG_INVALID_HANDLE) return; vgImageSubData - (vgImage, img.bits() + img.bytesPerLine() * (img.height() - 1), + (vgImage, qt_vg_imageBits(img) + img.bytesPerLine() * (img.height() - 1), -(img.bytesPerLine()), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height()); @@ -3658,15 +3676,17 @@ void QVGCompositionHelper::setScissor(const QRegion& region) vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data()); vgSeti(VG_SCISSORING, VG_TRUE); + d->scissorDirty = false; d->scissorActive = true; d->scissorRegion = region; } void QVGCompositionHelper::clearScissor() { - if (d->scissorActive) { + if (d->scissorActive || d->scissorDirty) { vgSeti(VG_SCISSORING, VG_FALSE); d->scissorActive = false; + d->scissorDirty = false; } } diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index 5d5fcbf..7de2212 100644 --- a/src/openvg/qpixmapdata_vg.cpp +++ b/src/openvg/qpixmapdata_vg.cpp @@ -43,6 +43,7 @@ #include "qpaintengine_vg_p.h" #include <QtGui/private/qdrawhelper_p.h> #include "qvg_p.h" +#include "qvgimagepool_p.h" #ifdef QT_SYMBIAN_SUPPORTS_SGIMAGE #include <graphics/sgimage.h> @@ -63,6 +64,8 @@ QVGPixmapData::QVGPixmapData(PixelType type) vgImageOpacity = VG_INVALID_HANDLE; cachedOpacity = 1.0f; recreate = true; + inImagePool = false; + inLRU = false; #if !defined(QT_NO_EGL) context = 0; qt_vg_register_pixmap(this); @@ -78,32 +81,43 @@ QVGPixmapData::~QVGPixmapData() #endif } +void QVGPixmapData::destroyImages() +{ + if (inImagePool) { + QVGImagePool *pool = QVGImagePool::instance(); + if (vgImage != VG_INVALID_HANDLE) + pool->releaseImage(this, vgImage); + if (vgImageOpacity != VG_INVALID_HANDLE) + pool->releaseImage(this, vgImageOpacity); + } else { + if (vgImage != VG_INVALID_HANDLE) + vgDestroyImage(vgImage); + if (vgImageOpacity != VG_INVALID_HANDLE) + vgDestroyImage(vgImageOpacity); + } + vgImage = VG_INVALID_HANDLE; + vgImageOpacity = VG_INVALID_HANDLE; + inImagePool = false; +} + void QVGPixmapData::destroyImageAndContext() { if (vgImage != VG_INVALID_HANDLE) { // We need to have a context current to destroy the image. #if !defined(QT_NO_EGL) if (context->isCurrent()) { - vgDestroyImage(vgImage); - if (vgImageOpacity != VG_INVALID_HANDLE) - vgDestroyImage(vgImageOpacity); + destroyImages(); } else { // We don't currently have a widget surface active, but we // need a surface to make the context current. So use the // shared pbuffer surface instead. context->makeCurrent(qt_vg_shared_surface()); - vgDestroyImage(vgImage); - if (vgImageOpacity != VG_INVALID_HANDLE) - vgDestroyImage(vgImageOpacity); + destroyImages(); context->lazyDoneCurrent(); } #else - vgDestroyImage(vgImage); - if (vgImageOpacity != VG_INVALID_HANDLE) - vgDestroyImage(vgImageOpacity); + destroyImages(); #endif - vgImage = VG_INVALID_HANDLE; - vgImageOpacity = VG_INVALID_HANDLE; } #if !defined(QT_NO_EGL) if (context) { @@ -218,7 +232,7 @@ QPaintEngine* QVGPixmapData::paintEngine() const // This function works around QImage::bits() making a deep copy if the // QImage is not const. We force it to be const and then get the bits. // XXX: Should add a QImage::constBits() in the future to replace this. -static inline const uchar *qt_vg_imageBits(const QImage& image) +const uchar *qt_vg_imageBits(const QImage& image) { return image.bits(); } @@ -234,22 +248,22 @@ VGImage QVGPixmapData::toVGImage() context = qt_vg_create_context(0, QInternal::Pixmap); #endif - if (recreate && prevSize != QSize(w, h)) { - if (vgImage != VG_INVALID_HANDLE) { - vgDestroyImage(vgImage); - vgImage = VG_INVALID_HANDLE; - } - if (vgImageOpacity != VG_INVALID_HANDLE) { - vgDestroyImage(vgImageOpacity); - vgImageOpacity = VG_INVALID_HANDLE; - } - } else if (recreate) { + if (recreate && prevSize != QSize(w, h)) + destroyImages(); + else if (recreate) cachedOpacity = -1.0f; // Force opacity image to be refreshed later. - } if (vgImage == VG_INVALID_HANDLE) { - vgImage = vgCreateImage - (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + vgImage = QVGImagePool::instance()->createImageForPixmap + (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this); + + // Bail out if we run out of GPU memory - try again next time. + if (vgImage == VG_INVALID_HANDLE) + return VG_INVALID_HANDLE; + + inImagePool = true; + } else if (inImagePool) { + QVGImagePool::instance()->useImage(this); } if (!source.isNull() && recreate) { @@ -278,8 +292,17 @@ VGImage QVGPixmapData::toVGImage(qreal opacity) // Create an alternative image for the selected opacity. if (vgImageOpacity == VG_INVALID_HANDLE || cachedOpacity != opacity) { if (vgImageOpacity == VG_INVALID_HANDLE) { - vgImageOpacity = vgCreateImage - (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + if (inImagePool) { + vgImageOpacity = QVGImagePool::instance()->createImageForPixmap + (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER, this); + } else { + vgImageOpacity = vgCreateImage + (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + } + + // Bail out if we run out of GPU memory - try again next time. + if (vgImageOpacity == VG_INVALID_HANDLE) + return VG_INVALID_HANDLE; } VGfloat matrix[20] = { 1.0f, 0.0f, 0.0f, 0.0f, @@ -300,6 +323,14 @@ VGImage QVGPixmapData::toVGImage(qreal opacity) #endif } +void QVGPixmapData::detachImageFromPool() +{ + if (inImagePool) { + QVGImagePool::instance()->detachImage(this); + inImagePool = false; + } +} + void QVGPixmapData::hibernate() { // If the image was imported (e.g, from an SgImage under Symbian), @@ -311,6 +342,14 @@ void QVGPixmapData::hibernate() destroyImageAndContext(); } +void QVGPixmapData::reclaimImages() +{ + if (!inImagePool) + return; + forceToImage(); + destroyImages(); +} + extern int qt_defaultDpiX(); extern int qt_defaultDpiY(); @@ -403,14 +442,7 @@ void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) if (!context) context = qt_vg_create_context(0, QInternal::Pixmap); - if (vgImage != VG_INVALID_HANDLE) { - vgDestroyImage(vgImage); - vgImage = VG_INVALID_HANDLE; - } - if (vgImageOpacity != VG_INVALID_HANDLE) { - vgDestroyImage(vgImageOpacity); - vgImageOpacity = VG_INVALID_HANDLE; - } + destroyImages(); prevSize = QSize(); TInt err = 0; diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h index c0bb098..4ff95c1 100644 --- a/src/openvg/qpixmapdata_vg_p.h +++ b/src/openvg/qpixmapdata_vg_p.h @@ -63,6 +63,7 @@ class RSGImage; QT_BEGIN_NAMESPACE class QEglContext; +class QVGImagePool; #if !defined(QT_NO_EGL) class QVGPixmapData; @@ -101,6 +102,9 @@ public: // Return the VGImage form for a specific opacity setting. virtual VGImage toVGImage(qreal opacity); + // Detach this image from the image pool. + virtual void detachImageFromPool(); + // Release the VG resources associated with this pixmap and copy // the pixmap's contents out of the GPU back into main memory. // The VG resource will be automatically recreated the next time @@ -109,6 +113,10 @@ public: // process via a SgImage). virtual void hibernate(); + // Called when the QVGImagePool wants to reclaim this pixmap's + // VGImage objects to reuse storage. + virtual void reclaimImages(); + QSize size() const { return QSize(w, h); } #if defined(Q_OS_SYMBIAN) @@ -123,8 +131,13 @@ protected: void cleanup(); #endif -#if !defined(QT_NO_EGL) private: + QVGPixmapData *nextLRU; + QVGPixmapData *prevLRU; + bool inLRU; + friend class QVGImagePool; + +#if !defined(QT_NO_EGL) QVGPixmapData *next; QVGPixmapData *prev; @@ -140,6 +153,7 @@ protected: qreal cachedOpacity; mutable QImage source; mutable bool recreate; + bool inImagePool; #if !defined(QT_NO_EGL) mutable QEglContext *context; #endif @@ -148,6 +162,7 @@ protected: QImage::Format sourceFormat() const; void destroyImageAndContext(); + void destroyImages(); }; QT_END_NAMESPACE diff --git a/src/openvg/qpixmapfilter_vg.cpp b/src/openvg/qpixmapfilter_vg.cpp index e17c728..aa526ed 100644 --- a/src/openvg/qpixmapfilter_vg.cpp +++ b/src/openvg/qpixmapfilter_vg.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qpixmapfilter_vg_p.h" +#include "qvgimagepool_p.h" #include <QtCore/qvarlengtharray.h> #include <QtGui/qpainter.h> @@ -82,9 +83,9 @@ void QVGPixmapConvolutionFilter::draw return; QSize size = pd->size(); - VGImage dstImage = vgCreateImage + VGImage dstImage = QVGImagePool::instance()->createTemporaryImage (VG_sARGB_8888_PRE, size.width(), size.height(), - VG_IMAGE_QUALITY_FASTER); + VG_IMAGE_QUALITY_FASTER, pd); if (dstImage == VG_INVALID_HANDLE) return; @@ -124,7 +125,7 @@ void QVGPixmapConvolutionFilter::draw if(child != dstImage) vgDestroyImage(child); - vgDestroyImage(dstImage); + QVGImagePool::instance()->releaseImage(0, dstImage); } QVGPixmapColorizeFilter::QVGPixmapColorizeFilter() @@ -155,9 +156,9 @@ void QVGPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const return; QSize size = pd->size(); - VGImage dstImage = vgCreateImage + VGImage dstImage = QVGImagePool::instance()->createTemporaryImage (VG_sARGB_8888_PRE, size.width(), size.height(), - VG_IMAGE_QUALITY_FASTER); + VG_IMAGE_QUALITY_FASTER, pd); if (dstImage == VG_INVALID_HANDLE) return; @@ -217,7 +218,7 @@ void QVGPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const if(child != dstImage) vgDestroyImage(child); - vgDestroyImage(dstImage); + QVGImagePool::instance()->releaseImage(0, dstImage); } QVGPixmapDropShadowFilter::QVGPixmapDropShadowFilter() @@ -248,9 +249,9 @@ void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, con return; QSize size = pd->size(); - VGImage dstImage = vgCreateImage + VGImage dstImage = QVGImagePool::instance()->createTemporaryImage (VG_A_8, size.width(), size.height(), - VG_IMAGE_QUALITY_FASTER); + VG_IMAGE_QUALITY_FASTER, pd); if (dstImage == VG_INVALID_HANDLE) return; @@ -282,7 +283,7 @@ void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, con if(child != dstImage) vgDestroyImage(child); - vgDestroyImage(dstImage); + QVGImagePool::instance()->releaseImage(0, dstImage); // Now draw the actual pixmap over the top. painter->drawPixmap(dest, src, srect); @@ -316,9 +317,9 @@ void QVGPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPi return; QSize size = pd->size(); - VGImage dstImage = vgCreateImage + VGImage dstImage = QVGImagePool::instance()->createTemporaryImage (VG_sARGB_8888_PRE, size.width(), size.height(), - VG_IMAGE_QUALITY_FASTER); + VG_IMAGE_QUALITY_FASTER, pd); if (dstImage == VG_INVALID_HANDLE) return; @@ -347,7 +348,7 @@ void QVGPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPi if(child != dstImage) vgDestroyImage(child); - vgDestroyImage(dstImage); + QVGImagePool::instance()->releaseImage(0, dstImage); } #endif diff --git a/src/openvg/qvgimagepool.cpp b/src/openvg/qvgimagepool.cpp new file mode 100644 index 0000000..93e6e03 --- /dev/null +++ b/src/openvg/qvgimagepool.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qvgimagepool_p.h" +#include "qpixmapdata_vg_p.h" + +QT_BEGIN_NAMESPACE + +static QVGImagePool *qt_vg_image_pool = 0; + +class QVGImagePoolPrivate +{ +public: + QVGImagePoolPrivate() : lruFirst(0), lruLast(0) {} + + QVGPixmapData *lruFirst; + QVGPixmapData *lruLast; +}; + +QVGImagePool::QVGImagePool() + : d_ptr(new QVGImagePoolPrivate()) +{ +} + +QVGImagePool::~QVGImagePool() +{ +} + +QVGImagePool *QVGImagePool::instance() +{ + if (!qt_vg_image_pool) + qt_vg_image_pool = new QVGImagePool(); + return qt_vg_image_pool; +} + +void QVGImagePool::setImagePool(QVGImagePool *pool) +{ + if (qt_vg_image_pool != pool) + delete qt_vg_image_pool; + qt_vg_image_pool = pool; +} + +VGImage QVGImagePool::createTemporaryImage(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality, + QVGPixmapData *keepData) +{ + VGImage image; + do { + image = vgCreateImage(format, width, height, allowedQuality); + if (image != VG_INVALID_HANDLE) + return image; + } while (reclaimSpace(format, width, height, keepData)); + qWarning("QVGImagePool: cannot reclaim sufficient space for a %dx%d temporary image", + width, height); + return VG_INVALID_HANDLE; +} + +VGImage QVGImagePool::createImageForPixmap(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality, + QVGPixmapData *data) +{ + VGImage image; + do { + image = vgCreateImage(format, width, height, allowedQuality); + if (image != VG_INVALID_HANDLE) { + if (data) + moveToHeadOfLRU(data); + return image; + } + } while (reclaimSpace(format, width, height, data)); + qWarning("QVGImagePool: cannot reclaim sufficient space for a %dx%d pixmap", + width, height); + return VG_INVALID_HANDLE; +} + +VGImage QVGImagePool::createPermanentImage(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality) +{ + VGImage image; + do { + image = vgCreateImage(format, width, height, allowedQuality); + if (image != VG_INVALID_HANDLE) + return image; + } while (reclaimSpace(format, width, height, 0)); + qWarning("QVGImagePool: cannot reclaim sufficient space for a %dx%d image", + width, height); + return VG_INVALID_HANDLE; +} + +void QVGImagePool::releaseImage(QVGPixmapData *data, VGImage image) +{ + // Very simple strategy at the moment: just destroy the image. + if (data) + removeFromLRU(data); + vgDestroyImage(image); +} + +void QVGImagePool::useImage(QVGPixmapData *data) +{ + moveToHeadOfLRU(data); +} + +void QVGImagePool::detachImage(QVGPixmapData *data) +{ + removeFromLRU(data); +} + +bool QVGImagePool::reclaimSpace(VGImageFormat format, + VGint width, VGint height, + QVGPixmapData *data) +{ + Q_UNUSED(format); // For future use in picking the best image to eject. + Q_UNUSED(width); + Q_UNUSED(height); + + if (data) + moveToHeadOfLRU(data); + + QVGPixmapData *lrudata = pixmapLRU(); + if (lrudata && lrudata != data) { + lrudata->reclaimImages(); + return true; + } + + return false; +} + +void QVGImagePool::hibernate() +{ + // Nothing to do here at the moment since the pool does not + // retain VGImage's after they have been released. +} + +void QVGImagePool::moveToHeadOfLRU(QVGPixmapData *data) +{ + Q_D(QVGImagePool); + if (data->inLRU) { + if (!data->prevLRU) + return; // Already at the head of the list. + removeFromLRU(data); + } + data->inLRU = true; + data->nextLRU = d->lruFirst; + data->prevLRU = 0; + if (d->lruFirst) + d->lruFirst->prevLRU = data; + else + d->lruLast = data; + d->lruFirst = data; +} + +void QVGImagePool::removeFromLRU(QVGPixmapData *data) +{ + Q_D(QVGImagePool); + if (!data->inLRU) + return; + if (data->nextLRU) + data->nextLRU->prevLRU = data->prevLRU; + else + d->lruLast = data->prevLRU; + if (data->prevLRU) + data->prevLRU->nextLRU = data->nextLRU; + else + d->lruFirst = data->nextLRU; + data->inLRU = false; +} + +QVGPixmapData *QVGImagePool::pixmapLRU() +{ + Q_D(QVGImagePool); + return d->lruLast; +} + +QT_END_NAMESPACE diff --git a/src/openvg/qvgimagepool_p.h b/src/openvg/qvgimagepool_p.h new file mode 100644 index 0000000..66a4998 --- /dev/null +++ b/src/openvg/qvgimagepool_p.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVGIMAGEPOOL_P_H +#define QVGIMAGEPOOL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qvg.h" +#include <QtCore/qscopedpointer.h> + +QT_BEGIN_NAMESPACE + +class QVGPixmapData; +class QVGImagePoolPrivate; + +class Q_OPENVG_EXPORT QVGImagePool +{ +public: + QVGImagePool(); + virtual ~QVGImagePool(); + + static QVGImagePool *instance(); + + // This function can be used from system-specific graphics system + // plugins to alter the image allocation strategy. + static void setImagePool(QVGImagePool *pool); + + // Create a new VGImage from the pool with the specified parameters + // that is not associated with a pixmap. The VGImage is returned to + // the pool when releaseImage() is called. + // + // This function will call reclaimSpace() when vgCreateImage() fails. + // + // This function is typically called when allocating temporary + // VGImage's for pixmap filters. The "keepData" object will not + // be reclaimed if reclaimSpace() needs to be called. + virtual VGImage createTemporaryImage(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality, + QVGPixmapData *keepData = 0); + + // Create a new VGImage with the specified parameters and associate + // it with "data". The QVGPixmapData will be notified when the + // VGImage needs to be reclaimed by the pool. + // + // This function will call reclaimSpace() when vgCreateImage() fails. + virtual VGImage createImageForPixmap(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality, + QVGPixmapData *data); + + // Create a permanent VGImage with the specified parameters. + // If there is insufficient space for the vgCreateImage call, + // then this function will call reclaimSpace() and try again. + // + // The caller is responsible for calling vgDestroyImage() + // when it no longer needs the VGImage, as the image is not + // recorded in the image pool. + // + // This function is typically used for pattern brushes where + // the OpenVG engine is responsible for managing the lifetime + // of the VGImage, destroying it automatically when the brush + // is no longer in use. + virtual VGImage createPermanentImage(VGImageFormat format, + VGint width, VGint height, + VGbitfield allowedQuality); + + // Release a VGImage that is no longer required. + virtual void releaseImage(QVGPixmapData *data, VGImage image); + + // Notify the pool that a QVGPixmapData object is using + // an image again. This allows the pool to move the image + // within a least-recently-used list of QVGPixmapData objects. + virtual void useImage(QVGPixmapData *data); + + // Notify the pool that the VGImage's associated with a + // QVGPixmapData are being detached from the pool. The caller + // will become responsible for calling vgDestroyImage(). + virtual void detachImage(QVGPixmapData *data); + + // Reclaim space for an image allocation with the specified parameters. + // Returns true if space was reclaimed, or false if there is no + // further space that can be reclaimed. The "data" parameter + // indicates the pixmap that is trying to obtain space which should + // not itself be reclaimed. + virtual bool reclaimSpace(VGImageFormat format, + VGint width, VGint height, + QVGPixmapData *data); + + // Hibernate the image pool because the context is about to be + // destroyed. All VGImage's left in the pool should be released. + virtual void hibernate(); + +protected: + // Helper functions for managing the LRU list of QVGPixmapData objects. + void moveToHeadOfLRU(QVGPixmapData *data); + void removeFromLRU(QVGPixmapData *data); + QVGPixmapData *pixmapLRU(); + +private: + QScopedPointer<QVGImagePoolPrivate> d_ptr; + + Q_DECLARE_PRIVATE(QVGImagePool) + Q_DISABLE_COPY(QVGImagePool) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qwindowsurface_vgegl.cpp b/src/openvg/qwindowsurface_vgegl.cpp index 1571083..bda6096 100644 --- a/src/openvg/qwindowsurface_vgegl.cpp +++ b/src/openvg/qwindowsurface_vgegl.cpp @@ -42,6 +42,7 @@ #include "qwindowsurface_vgegl_p.h" #include "qpaintengine_vg_p.h" #include "qpixmapdata_vg_p.h" +#include "qvgimagepool_p.h" #include "qvg_p.h" #if !defined(QT_NO_EGL) @@ -360,6 +361,9 @@ void qt_vg_hibernate_pixmaps(QVGSharedContext *shared) pd = pd->next; } + // Hibernate any remaining VGImage's in the image pool. + QVGImagePool::instance()->hibernate(); + // Don't need the current context any more. shared->context->lazyDoneCurrent(); diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp index c86af73..47b8786 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -103,6 +103,8 @@ public: void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos); void blit(const QRectF &dest, IDirectFBSurface *surface, const QRectF &src); + inline bool supportsStretchBlit() const; + inline void updateClip(); virtual void systemStateChanged(); @@ -526,11 +528,12 @@ void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image, #if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedBlits) || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) - || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip + || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) + || (!d->supportsStretchBlit() && state()->matrix.mapRect(r).size() != sr.size()) #ifndef QT_DIRECTFB_IMAGECACHE - || QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN + || (QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN) #elif defined QT_NO_DIRECTFB_PREALLOCATED - || QDirectFBPaintEnginePrivate::cacheCost(image) > imageCache.maxCost() + || (QDirectFBPaintEnginePrivate::cacheCost(image) > imageCache.maxCost()) #endif ) #endif @@ -573,10 +576,9 @@ void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedBlits) - || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) - || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip - || (state()->renderHints & QPainter::SmoothPixmapTransform - && state()->matrix.mapRect(r).size() != sr.size())) { + || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) + || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) + || (!d->supportsStretchBlit() && state()->matrix.mapRect(r).size() != sr.size())) { RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr); const QImage *img = dfbData->buffer(); d->lock(); @@ -606,8 +608,8 @@ void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r, QRasterPaintEngine::drawTiledPixmap(r, pixmap, offset); } else if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedBlits) || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) - || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip - || (state()->renderHints & QPainter::SmoothPixmapTransform && state()->matrix.isScaling())) { + || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) + || (!d->supportsStretchBlit() && state()->matrix.isScaling())) { RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset); QPixmapData *pixmapData = pixmap.pixmapData(); Q_ASSERT(pixmapData->classId() == QPixmapData::DirectFBClass); @@ -732,7 +734,7 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) case Qt::TexturePattern: { if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedBlits) || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) - || (state()->renderHints & QPainter::SmoothPixmapTransform && state()->matrix.isScaling())) { + || (!d->supportsStretchBlit() && state()->matrix.isScaling())) { break; } @@ -757,7 +759,7 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QColor &color) return; Q_D(QDirectFBPaintEngine); if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) - || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip + || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) || !d->testCompositionMode(0, 0, &color)) { RASTERFALLBACK(FILL_RECT, rect, color, VOID_ARG()); d->lock(); @@ -1049,6 +1051,7 @@ void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s, if (dr.size() == sr.size()) { result = surface->Blit(surface, s, &sRect, dr.x(), dr.y()); } else { + Q_ASSERT(supportsStretchBlit()); const DFBRectangle dRect = { dr.x(), dr.y(), dr.width(), dr.height() }; result = surface->StretchBlit(surface, s, &sRect, &dRect); } @@ -1096,6 +1099,7 @@ void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPix const QSize pixmapSize = dfbData->size(); IDirectFBSurface *sourceSurface = dfbData->directFBSurface(); if (transform.isScaling()) { + Q_ASSERT(supportsStretchBlit()); Q_ASSERT(qMin(transform.m11(), transform.m22()) >= 0); offset.rx() *= transform.m11(); offset.ry() *= transform.m22(); @@ -1184,6 +1188,16 @@ void QDirectFBPaintEnginePrivate::updateClip() } } +bool QDirectFBPaintEnginePrivate::supportsStretchBlit() const +{ +#ifdef QT_DIRECTFB_STRETCHBLIT + return !(q->state()->renderHints & QPainter::SmoothPixmapTransform); +#else + return false; +#endif +} + + void QDirectFBPaintEnginePrivate::systemStateChanged() { QRasterPaintEnginePrivate::systemStateChanged(); diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp index b15888b..e78966c 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp @@ -470,6 +470,7 @@ QPixmap QDirectFBPixmapData::transformed(const QTransform &transform, return QPixmap(); QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType); + data->setSerialNumber(++global_ser_no); DFBSurfaceBlittingFlags flags = DSBLIT_NOFX; data->alpha = alpha; if (alpha) { diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp index 4cb0184..bb26d29 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp @@ -958,47 +958,47 @@ struct FlagDescription { }; static const FlagDescription accelerationDescriptions[] = { - { " DFXL_NONE ", DFXL_NONE }, - { " DFXL_FILLRECTANGLE", DFXL_FILLRECTANGLE }, - { " DFXL_DRAWRECTANGLE", DFXL_DRAWRECTANGLE }, - { " DFXL_DRAWLINE", DFXL_DRAWLINE }, - { " DFXL_FILLTRIANGLE", DFXL_FILLTRIANGLE }, - { " DFXL_BLIT", DFXL_BLIT }, - { " DFXL_STRETCHBLIT", DFXL_STRETCHBLIT }, - { " DFXL_TEXTRIANGLES", DFXL_TEXTRIANGLES }, - { " DFXL_DRAWSTRING", DFXL_DRAWSTRING }, + { "DFXL_NONE", DFXL_NONE }, + { "DFXL_FILLRECTANGLE", DFXL_FILLRECTANGLE }, + { "DFXL_DRAWRECTANGLE", DFXL_DRAWRECTANGLE }, + { "DFXL_DRAWLINE", DFXL_DRAWLINE }, + { "DFXL_FILLTRIANGLE", DFXL_FILLTRIANGLE }, + { "DFXL_BLIT", DFXL_BLIT }, + { "DFXL_STRETCHBLIT", DFXL_STRETCHBLIT }, + { "DFXL_TEXTRIANGLES", DFXL_TEXTRIANGLES }, + { "DFXL_DRAWSTRING", DFXL_DRAWSTRING }, { 0, 0 } }; static const FlagDescription blitDescriptions[] = { - { " DSBLIT_NOFX", DSBLIT_NOFX }, - { " DSBLIT_BLEND_ALPHACHANNEL", DSBLIT_BLEND_ALPHACHANNEL }, - { " DSBLIT_BLEND_COLORALPHA", DSBLIT_BLEND_COLORALPHA }, - { " DSBLIT_COLORIZE", DSBLIT_COLORIZE }, - { " DSBLIT_SRC_COLORKEY", DSBLIT_SRC_COLORKEY }, - { " DSBLIT_DST_COLORKEY", DSBLIT_DST_COLORKEY }, - { " DSBLIT_SRC_PREMULTIPLY", DSBLIT_SRC_PREMULTIPLY }, - { " DSBLIT_DST_PREMULTIPLY", DSBLIT_DST_PREMULTIPLY }, - { " DSBLIT_DEMULTIPLY", DSBLIT_DEMULTIPLY }, - { " DSBLIT_DEINTERLACE", DSBLIT_DEINTERLACE }, + { "DSBLIT_NOFX", DSBLIT_NOFX }, + { "DSBLIT_BLEND_ALPHACHANNEL", DSBLIT_BLEND_ALPHACHANNEL }, + { "DSBLIT_BLEND_COLORALPHA", DSBLIT_BLEND_COLORALPHA }, + { "DSBLIT_COLORIZE", DSBLIT_COLORIZE }, + { "DSBLIT_SRC_COLORKEY", DSBLIT_SRC_COLORKEY }, + { "DSBLIT_DST_COLORKEY", DSBLIT_DST_COLORKEY }, + { "DSBLIT_SRC_PREMULTIPLY", DSBLIT_SRC_PREMULTIPLY }, + { "DSBLIT_DST_PREMULTIPLY", DSBLIT_DST_PREMULTIPLY }, + { "DSBLIT_DEMULTIPLY", DSBLIT_DEMULTIPLY }, + { "DSBLIT_DEINTERLACE", DSBLIT_DEINTERLACE }, #if (Q_DIRECTFB_VERSION >= 0x000923) - { " DSBLIT_SRC_PREMULTCOLOR", DSBLIT_SRC_PREMULTCOLOR }, - { " DSBLIT_XOR", DSBLIT_XOR }, + { "DSBLIT_SRC_PREMULTCOLOR", DSBLIT_SRC_PREMULTCOLOR }, + { "DSBLIT_XOR", DSBLIT_XOR }, #endif #if (Q_DIRECTFB_VERSION >= 0x010000) - { " DSBLIT_INDEX_TRANSLATION", DSBLIT_INDEX_TRANSLATION }, + { "DSBLIT_INDEX_TRANSLATION", DSBLIT_INDEX_TRANSLATION }, #endif { 0, 0 } }; static const FlagDescription drawDescriptions[] = { - { " DSDRAW_NOFX", DSDRAW_NOFX }, - { " DSDRAW_BLEND", DSDRAW_BLEND }, - { " DSDRAW_DST_COLORKEY", DSDRAW_DST_COLORKEY }, - { " DSDRAW_SRC_PREMULTIPLY", DSDRAW_SRC_PREMULTIPLY }, - { " DSDRAW_DST_PREMULTIPLY", DSDRAW_DST_PREMULTIPLY }, - { " DSDRAW_DEMULTIPLY", DSDRAW_DEMULTIPLY }, - { " DSDRAW_XOR", DSDRAW_XOR }, + { "DSDRAW_NOFX", DSDRAW_NOFX }, + { "DSDRAW_BLEND", DSDRAW_BLEND }, + { "DSDRAW_DST_COLORKEY", DSDRAW_DST_COLORKEY }, + { "DSDRAW_SRC_PREMULTIPLY", DSDRAW_SRC_PREMULTIPLY }, + { "DSDRAW_DST_PREMULTIPLY", DSDRAW_DST_PREMULTIPLY }, + { "DSDRAW_DEMULTIPLY", DSDRAW_DEMULTIPLY }, + { "DSDRAW_XOR", DSDRAW_XOR }, { 0, 0 } }; #endif @@ -1063,7 +1063,7 @@ static inline bool setIntOption(const QStringList &arguments, const QString &var static inline QColor colorFromName(const QString &name) { - QRegExp rx("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])"); + QRegExp rx(QLatin1String("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])")); rx.setCaseSensitivity(Qt::CaseInsensitive); if (rx.exactMatch(name)) { Q_ASSERT(rx.captureCount() == 4); @@ -1259,11 +1259,14 @@ bool QDirectFBScreen::connect(const QString &displaySpec) setIntOption(displayArgs, QLatin1String("height"), &h); #ifndef QT_NO_DIRECTFB_LAYER - result = d_ptr->dfb->GetDisplayLayer(d_ptr->dfb, DLID_PRIMARY, + int layerId = DLID_PRIMARY; + setIntOption(displayArgs, QLatin1String("layerid"), &layerId); + + result = d_ptr->dfb->GetDisplayLayer(d_ptr->dfb, static_cast<DFBDisplayLayerID>(layerId), &d_ptr->dfbLayer); if (result != DFB_OK) { DirectFBError("QDirectFBScreen::connect: " - "Unable to get primary display layer!", result); + "Unable to get display layer!", result); return false; } result = d_ptr->dfbLayer->GetScreen(d_ptr->dfbLayer, &d_ptr->dfbScreen); @@ -1275,7 +1278,14 @@ bool QDirectFBScreen::connect(const QString &displaySpec) #ifdef QT_NO_DIRECTFB_WM result = d_ptr->primarySurface->GetSize(d_ptr->primarySurface, &w, &h); #elif (Q_DIRECTFB_VERSION >= 0x010000) - result = d_ptr->dfbScreen->GetSize(d_ptr->dfbScreen, &w, &h); + IDirectFBSurface *layerSurface; + if (d_ptr->dfbLayer->GetSurface(d_ptr->dfbLayer, &layerSurface) != DFB_OK) { + result = layerSurface->GetSize(layerSurface, &w, &h); + layerSurface->Release(layerSurface); + } + if (w <= 0 || h <= 0) { + result = d_ptr->dfbScreen->GetSize(d_ptr->dfbScreen, &w, &h); + } #else qWarning("QDirectFBScreen::connect: DirectFB versions prior to 1.0 do not offer a way\n" "query the size of the primary surface in windowed mode. You have to specify\n" diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h index 6330582..61d9cf1 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h @@ -69,6 +69,9 @@ QT_MODULE(Gui) #if !defined QT_NO_DIRECTFB_IMAGEPROVIDER && !defined QT_DIRECTFB_IMAGEPROVIDER #define QT_DIRECTFB_IMAGEPROVIDER #endif +#if !defined QT_NO_DIRECTFB_STRETCHBLIT && !defined QT_DIRECTFB_STRETCHBLIT +#define QT_DIRECTFB_STRETCHBLIT +#endif #if !defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE && !defined QT_NO_DIRECTFB_IMAGEPROVIDER_KEEPALIVE #define QT_NO_DIRECTFB_IMAGEPROVIDER_KEEPALIVE #endif diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp index 021d52e..b79418a 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp @@ -128,7 +128,6 @@ IDirectFBWindow *QDirectFBWindowSurface::directFBWindow() const return (dfbWindow ? dfbWindow : (sibling ? sibling->dfbWindow : 0)); } - void QDirectFBWindowSurface::createWindow(const QRect &rect) { IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer(); @@ -169,6 +168,9 @@ void QDirectFBWindowSurface::createWindow(const QRect &rect) DirectFBErrorFatal("QDirectFBWindowSurface::createWindow", result); if (window()) { + if (window()->windowFlags() & Qt::WindowStaysOnTopHint) { + dfbWindow->SetStackingClass(dfbWindow, DWSC_UPPER); + } DFBWindowID winid; result = dfbWindow->GetID(dfbWindow, &winid); if (result != DFB_OK) { diff --git a/src/plugins/imageformats/gif/qgifhandler.cpp b/src/plugins/imageformats/gif/qgifhandler.cpp index c95b63c..dee0e52 100644 --- a/src/plugins/imageformats/gif/qgifhandler.cpp +++ b/src/plugins/imageformats/gif/qgifhandler.cpp @@ -54,6 +54,10 @@ QT_BEGIN_NAMESPACE #define Q_TRANSPARENT 0x00ffffff +// avoid going through QImage::scanLine() which calls detach +#define FAST_SCAN_LINE(bits, bpl, y) (bits + (y) * bpl) + + /* Incremental image decoder for GIF image format. @@ -135,7 +139,7 @@ private: int frame; bool out_of_bounds; bool digress; - void nextY(QImage *image); + void nextY(unsigned char *bits, int bpl); void disposePrevious(QImage *image); }; @@ -232,6 +236,10 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length, // CompuServe Incorporated. GIF(sm) is a Service Mark property of // CompuServe Incorporated." + image->detach(); + int bpl = image->bytesPerLine(); + unsigned char *bits = image->bits(); + #define LM(l, m) (((m)<<8)|l) digress = false; const int initial = length; @@ -335,7 +343,9 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length, QImage::Format format = trans_index >= 0 ? QImage::Format_ARGB32 : QImage::Format_RGB32; if (image->isNull()) { (*image) = QImage(swidth, sheight, format); - memset(image->bits(), 0, image->byteCount()); + bpl = image->bytesPerLine(); + bits = image->bits(); + memset(bits, 0, image->byteCount()); // ### size of the upcoming frame, should rather // be known before decoding it. @@ -393,11 +403,13 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length, backingstore = QImage(qMax(backingstore.width(), w), qMax(backingstore.height(), h), QImage::Format_RGB32); - memset(image->bits(), 0, image->byteCount()); + memset(bits, 0, image->byteCount()); } + const int dest_bpl = backingstore.bytesPerLine(); + unsigned char *dest_data = backingstore.bits(); for (int ln=0; ln<h; ln++) { - memcpy(backingstore.scanLine(ln), - image->scanLine(t+ln)+l, w*sizeof(QRgb)); + memcpy(FAST_SCAN_LINE(dest_data, dest_bpl, ln), + FAST_SCAN_LINE(bits, bpl, t+ln) + l, w*sizeof(QRgb)); } } @@ -470,14 +482,14 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length, if (needfirst) { firstcode=oldcode=code; if (!out_of_bounds && image->height() > y && firstcode!=trans_index) - ((QRgb*)image->scanLine(y))[x] = color(firstcode); + ((QRgb*)FAST_SCAN_LINE(bits, bpl, y))[x] = color(firstcode); x++; if (x>=swidth) out_of_bounds = true; needfirst=false; if (x>=left+width) { x=left; out_of_bounds = left>=swidth || y>=sheight; - nextY(image); + nextY(bits, bpl); } } else { incode=code; @@ -515,7 +527,7 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length, const QRgb *map = lcmap ? localcmap : globalcmap; QRgb *line = 0; if (!out_of_bounds && h > y) - line = (QRgb*)image->scanLine(y); + line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y); while (sp>stack) { const uchar index = *(--sp); if (!out_of_bounds && h > y && index!=trans_index) { @@ -529,9 +541,9 @@ int QGIFFormat::decode(QImage *image, const uchar *buffer, int length, if (x>=left+width) { x=left; out_of_bounds = left>=swidth || y>=sheight; - nextY(image); + nextY(bits, bpl); if (!out_of_bounds && h > y) - line = (QRgb*)image->scanLine(y); + line = (QRgb*)FAST_SCAN_LINE(bits, bpl, y); } } } @@ -644,7 +656,7 @@ void QGIFFormat::fillRect(QImage *image, int col, int row, int w, int h, QRgb co } } -void QGIFFormat::nextY(QImage *image) +void QGIFFormat::nextY(unsigned char *bits, int bpl) { int my; switch (interlace) { @@ -660,7 +672,7 @@ void QGIFFormat::nextY(QImage *image) // Don't dup with transparency if (trans_index < 0) { for (i=1; i<=my; i++) { - memcpy(image->scanLine(y+i)+left*sizeof(QRgb), image->scanLine(y)+left*sizeof(QRgb), + memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb), (right-left+1)*sizeof(QRgb)); } } @@ -689,7 +701,7 @@ void QGIFFormat::nextY(QImage *image) // Don't dup with transparency if (trans_index < 0) { for (i=1; i<=my; i++) { - memcpy(image->scanLine(y+i)+left*sizeof(QRgb), image->scanLine(y)+left*sizeof(QRgb), + memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb), (right-left+1)*sizeof(QRgb)); } } @@ -713,7 +725,7 @@ void QGIFFormat::nextY(QImage *image) // Don't dup with transparency if (trans_index < 0) { for (i=1; i<=my; i++) { - memcpy(image->scanLine(y+i)+left*sizeof(QRgb), image->scanLine(y)+left*sizeof(QRgb), + memcpy(FAST_SCAN_LINE(bits, bpl, y+i)+left*sizeof(QRgb), FAST_SCAN_LINE(bits, bpl, y)+left*sizeof(QRgb), (right-left+1)*sizeof(QRgb)); } } diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index 54bbcda..11608ef 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -84,15 +84,12 @@ class QImageSmoothScaler public: QImageSmoothScaler(const int w, const int h, const QImage &src); QImageSmoothScaler(const int srcWidth, const int srcHeight, - const char *parameters); + const int dstWidth, const int dstHeight); virtual ~QImageSmoothScaler(void); QImage scale(); -protected: - int scaledWidth(void) const; - private: QImageSmoothScalerPrivate *d; virtual QRgb *scanLine(const int line = 0, const QImage *src = 0); @@ -123,33 +120,9 @@ QImageSmoothScaler::QImageSmoothScaler(const int w, const int h, } QImageSmoothScaler::QImageSmoothScaler(const int srcWidth, const int srcHeight, - const char *parameters) + const int dstWidth, const int dstHeight) { - char sModeStr[1024]; - int t1; - int t2; - int dstWidth; - int dstHeight; - - sModeStr[0] = '\0'; - d = new QImageSmoothScalerPrivate; -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400 - sscanf_s(parameters, "Scale( %i, %i, %1023s )", &dstWidth, &dstHeight, sModeStr, sizeof(sModeStr)); -#else - sscanf(parameters, "Scale( %i, %i, %s )", &dstWidth, &dstHeight, sModeStr); -#endif - QString sModeQStr = QString::fromLatin1(sModeStr); - - t1 = srcWidth * dstHeight; - t2 = srcHeight * dstWidth; - - if (((sModeQStr == QLatin1String("ScaleMin")) && (t1 > t2)) || ((sModeQStr == QLatin1String("ScaleMax")) && (t2 < t2))) { - dstHeight = t2 / srcWidth; - } else if (sModeQStr != QLatin1String("ScaleFree")) { - dstWidth = t1 / srcHeight; - } - d->setup(srcWidth, srcHeight, dstWidth, dstHeight, 0); } @@ -164,11 +137,6 @@ void QImageSmoothScalerPrivate::setup(const int srcWidth, const int srcHeight, hasAlpha = hasAlphaChannel; } -int QImageSmoothScaler::scaledWidth() const -{ - return d->cols; -} - QImageSmoothScaler::~QImageSmoothScaler() { delete d; @@ -467,20 +435,18 @@ QImage QImageSmoothScaler::scale() class jpegSmoothScaler : public QImageSmoothScaler { public: - jpegSmoothScaler(struct jpeg_decompress_struct *info, const char *params): - QImageSmoothScaler(info->output_width, info->output_height, params) + jpegSmoothScaler(struct jpeg_decompress_struct *info, const QSize& dstSize, const QRect& clipRect) + : QImageSmoothScaler(clipRect.width(), clipRect.height(), + dstSize.width(), dstSize.height()) { - cinfo = info; - cols24Bit = scaledWidth() * 3; - - cacheHeight = 1; - imageCache = QImage( info->output_width, cacheHeight, QImage::Format_RGB32 ); + cinfo = info; + clip = clipRect; + imageCache = QImage(info->output_width, 1, QImage::Format_RGB32); } private: - int cols24Bit; + QRect clip; QImage imageCache; - int cacheHeight; struct jpeg_decompress_struct *cinfo; QRgb *scanLine(const int line = 0, const QImage *src = 0) @@ -492,33 +458,42 @@ private: Q_UNUSED(src); uchar* data = imageCache.bits(); + + // Read ahead if we haven't reached the first clipped scanline yet. + while (int(cinfo->output_scanline) < clip.y() && + cinfo->output_scanline < cinfo->output_height) + jpeg_read_scanlines(cinfo, &data, 1); + + // Read the next scanline. We assume that "line" + // will never be >= clip.height(). jpeg_read_scanlines(cinfo, &data, 1); - out = (QRgb*)imageCache.scanLine(0); + if (cinfo->output_scanline == cinfo->output_height) + jpeg_finish_decompress(cinfo); + + out = ((QRgb*)data) + clip.x(); // // The smooth scale algorithm only works on 32-bit images; // convert from (8|24) bits to 32. // if (cinfo->output_components == 1) { - in = (uchar*)out + scaledWidth(); - for (uint i = scaledWidth(); i--; ) { - in--; + in = data + clip.right(); + for (int i = clip.width(); i--; ) { out[i] = qRgb(*in, *in, *in); + in--; } - } else if (cinfo->out_color_space == JCS_CMYK) { - int cols32Bit = scaledWidth() * 4; - in = (uchar*)out + cols32Bit; - for (uint i = scaledWidth(); i--; ) { - in -= 4; - int k = in[3]; - out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255); - //out[i] = qRgb(in[0], in[1], in[2]); - } - } else { - in = (uchar*)out + cols24Bit; - for (uint i = scaledWidth(); i--; ) { - in -= 3; + } else if (cinfo->out_color_space == JCS_CMYK) { + in = data + clip.right() * 4; + for (int i = clip.width(); i--; ) { + int k = in[3]; + out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255); + in -= 4; + } + } else { + in = data + clip.right() * 3; + for (int i = clip.width(); i--; ) { out[i] = qRgb(in[0], in[1], in[2]); + in -= 3; } } @@ -637,18 +612,6 @@ inline my_jpeg_source_mgr::my_jpeg_source_mgr(QIODevice *device) } -static void scaleSize(int &reqW, int &reqH, int imgW, int imgH, Qt::AspectRatioMode mode) -{ - if (mode == Qt::IgnoreAspectRatio) - return; - int t1 = imgW * reqH; - int t2 = reqW * imgH; - if ((mode == Qt::KeepAspectRatio && (t1 > t2)) || (mode == Qt::KeepAspectRatioByExpanding && (t1 < t2))) - reqH = t2 / imgW; - else - reqW = t1 / imgH; -} - static bool read_jpeg_size(QIODevice *device, int &w, int &h) { bool rt = false; @@ -729,7 +692,7 @@ static bool read_jpeg_format(QIODevice *device, QImage::Format &format) } static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, - bool dummy = false) + const QSize& size) { QImage::Format format; switch (info->output_components) { @@ -744,13 +707,8 @@ static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, return false; // unsupported format } - const QSize size(info->output_width, info->output_height); if (dest->size() != size || dest->format() != format) { - static uchar dummyImage[1]; - if (dummy) // Create QImage but don't read the pixels - *dest = QImage(dummyImage, size.width(), size.height(), format); - else - *dest = QImage(size, format); + *dest = QImage(size, format); if (format == QImage::Format_Indexed8) { dest->setColorCount(256); @@ -763,13 +721,9 @@ static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, } static bool read_jpeg_image(QIODevice *device, QImage *outImage, - const QByteArray ¶meters, QSize scaledSize, - int inQuality ) + QSize scaledSize, QRect scaledClipRect, + QRect clipRect, int inQuality ) { -#ifdef QT_NO_IMAGE_SMOOTHSCALE - Q_UNUSED( scaledSize ); -#endif - struct jpeg_decompress_struct cinfo; struct my_jpeg_source_mgr *iod_src = new my_jpeg_source_mgr(device); @@ -794,18 +748,53 @@ static bool read_jpeg_image(QIODevice *device, QImage *outImage, if (quality < 0) quality = 75; - QString params = QString::fromLatin1(parameters); - params.simplified(); - int sWidth = 0, sHeight = 0; - char sModeStr[1024] = ""; - Qt::AspectRatioMode sMode; + // If possible, merge the scaledClipRect into either scaledSize + // or clipRect to avoid doing a separate scaled clipping pass. + // Best results are achieved by clipping before scaling, not after. + if (!scaledClipRect.isEmpty()) { + if (scaledSize.isEmpty() && clipRect.isEmpty()) { + // No clipping or scaling before final clip. + clipRect = scaledClipRect; + scaledClipRect = QRect(); + } else if (scaledSize.isEmpty()) { + // Clipping, but no scaling: combine the clip regions. + scaledClipRect.translate(clipRect.topLeft()); + clipRect = scaledClipRect.intersected(clipRect); + scaledClipRect = QRect(); + } else if (clipRect.isEmpty()) { + // No clipping, but scaling: if we can map back to an + // integer pixel boundary, then clip before scaling. + if ((cinfo.image_width % scaledSize.width()) == 0 && + (cinfo.image_height % scaledSize.height()) == 0) { + int x = scaledClipRect.x() * cinfo.image_width / + scaledSize.width(); + int y = scaledClipRect.y() * cinfo.image_height / + scaledSize.height(); + int width = (scaledClipRect.right() + 1) * + cinfo.image_width / scaledSize.width() - x; + int height = (scaledClipRect.bottom() + 1) * + cinfo.image_height / scaledSize.height() - y; + clipRect = QRect(x, y, width, height); + scaledSize = scaledClipRect.size(); + scaledClipRect = QRect(); + } + } else { + // Clipping and scaling: too difficult to figure out, + // and not a likely use case, so do it the long way. + } + } -#ifndef QT_NO_IMAGE_SMOOTHSCALE - // If high quality not required, shrink image during decompression - if (scaledSize.isValid() && !scaledSize.isEmpty() && quality < HIGH_QUALITY_THRESHOLD - && !params.contains(QLatin1String("GetHeaderInformation")) ) { - cinfo.scale_denom = qMin(cinfo.image_width / scaledSize.width(), - cinfo.image_width / scaledSize.height()); + // Determine the scale factor to pass to libjpeg for quick downscaling. + if (!scaledSize.isEmpty()) { + if (clipRect.isEmpty()) { + cinfo.scale_denom = + qMin(cinfo.image_width / scaledSize.width(), + cinfo.image_height / scaledSize.height()); + } else { + cinfo.scale_denom = + qMin(clipRect.width() / scaledSize.width(), + clipRect.height() / scaledSize.height()); + } if (cinfo.scale_denom < 2) { cinfo.scale_denom = 1; } else if (cinfo.scale_denom < 4) { @@ -816,9 +805,19 @@ static bool read_jpeg_image(QIODevice *device, QImage *outImage, cinfo.scale_denom = 8; } cinfo.scale_num = 1; + if (!clipRect.isEmpty()) { + // Correct the scale factor so that we clip accurately. + // It is recommended that the clip rectangle be aligned + // on an 8-pixel boundary for best performance. + while (cinfo.scale_denom > 1 && + ((clipRect.x() % cinfo.scale_denom) != 0 || + (clipRect.y() % cinfo.scale_denom) != 0 || + (clipRect.width() % cinfo.scale_denom) != 0 || + (clipRect.height() % cinfo.scale_denom) != 0)) { + cinfo.scale_denom /= 2; + } + } } -#endif - // If high quality not required, use fast decompression if( quality < HIGH_QUALITY_THRESHOLD ) { @@ -826,132 +825,102 @@ static bool read_jpeg_image(QIODevice *device, QImage *outImage, cinfo.do_fancy_upsampling = FALSE; } + (void) jpeg_calc_output_dimensions(&cinfo); - (void) jpeg_start_decompress(&cinfo); + // Determine the clip region to extract. + QRect imageRect(0, 0, cinfo.output_width, cinfo.output_height); + QRect clip; + if (clipRect.isEmpty()) { + clip = imageRect; + } else if (cinfo.scale_denom == 1) { + clip = clipRect.intersected(imageRect); + } else { + // The scale factor was corrected above to ensure that + // we don't miss pixels when we scale the clip rectangle. + clip = QRect(clipRect.x() / int(cinfo.scale_denom), + clipRect.y() / int(cinfo.scale_denom), + clipRect.width() / int(cinfo.scale_denom), + clipRect.height() / int(cinfo.scale_denom)); + clip = clip.intersected(imageRect); + } - if (params.contains(QLatin1String("GetHeaderInformation"))) { - if (!ensureValidImage(outImage, &cinfo, true)) - longjmp(jerr.setjmp_buffer, 1); - } else if (params.contains(QLatin1String("Scale"))) { -#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(Q_OS_WINCE) - sscanf_s(params.toLatin1().data(), "Scale(%i, %i, %1023s)", - &sWidth, &sHeight, sModeStr, sizeof(sModeStr)); -#else - sscanf(params.toLatin1().data(), "Scale(%i, %i, %1023s)", - &sWidth, &sHeight, sModeStr); -#endif +#ifndef QT_NO_IMAGE_SMOOTHSCALE + if (scaledSize.isValid() && scaledSize != clip.size() + && quality >= HIGH_QUALITY_THRESHOLD) { - QString sModeQStr(QString::fromLatin1(sModeStr)); - if (sModeQStr == QLatin1String("IgnoreAspectRatio")) { - sMode = Qt::IgnoreAspectRatio; - } else if (sModeQStr == QLatin1String("KeepAspectRatio")) { - sMode = Qt::KeepAspectRatio; - } else if (sModeQStr == QLatin1String("KeepAspectRatioByExpanding")) { - sMode = Qt::KeepAspectRatioByExpanding; - } else { - qDebug("read_jpeg_image: invalid aspect ratio mode \"%s\", see QImage::AspectRatioMode documentation", sModeStr); - sMode = Qt::KeepAspectRatio; - } + (void) jpeg_start_decompress(&cinfo); -// qDebug("Parameters ask to scale the image to %i x %i AspectRatioMode: %s", sWidth, sHeight, sModeStr); - scaleSize(sWidth, sHeight, cinfo.output_width, cinfo.output_height, sMode); -// qDebug("Scaling the jpeg to %i x %i", sWidth, sHeight, sModeStr); - - if (cinfo.output_components == 3 || cinfo.output_components == 4) { - if (outImage->size() != QSize(sWidth, sHeight) || outImage->format() != QImage::Format_RGB32) - *outImage = QImage(sWidth, sHeight, QImage::Format_RGB32); - } else if (cinfo.output_components == 1) { - if (outImage->size() != QSize(sWidth, sHeight) || outImage->format() != QImage::Format_Indexed8) - *outImage = QImage(sWidth, sHeight, QImage::Format_Indexed8); - outImage->setColorCount(256); - for (int i = 0; i < 256; ++i) - outImage->setColor(i, qRgb(i,i,i)); - } else { - // Unsupported format - } - if (outImage->isNull()) + jpegSmoothScaler scaler(&cinfo, scaledSize, clip); + *outImage = scaler.scale(); + } else +#endif + { + // Allocate memory for the clipped QImage. + if (!ensureValidImage(outImage, &cinfo, clip.size())) longjmp(jerr.setjmp_buffer, 1); - if (!outImage->isNull()) { - QImage tmpImage(cinfo.output_width, 1, QImage::Format_RGB32); - uchar* inData = tmpImage.bits(); - uchar* outData = outImage->bits(); - int out_bpl = outImage->bytesPerLine(); + // Avoid memcpy() overhead if grayscale with no clipping. + bool quickGray = (cinfo.output_components == 1 && + clip == imageRect); + if (!quickGray) { + // Ask the jpeg library to allocate a temporary row. + // The library will automatically delete it for us later. + // The libjpeg docs say we should do this before calling + // jpeg_start_decompress(). We can't use "new" here + // because we are inside the setjmp() block and an error + // in the jpeg input stream would cause a memory leak. + JSAMPARRAY rows = (cinfo.mem->alloc_sarray) + ((j_common_ptr)&cinfo, JPOOL_IMAGE, + cinfo.output_width * cinfo.output_components, 1); + + (void) jpeg_start_decompress(&cinfo); + while (cinfo.output_scanline < cinfo.output_height) { - int outputLine = sHeight * cinfo.output_scanline / cinfo.output_height; - (void) jpeg_read_scanlines(&cinfo, &inData, 1); + int y = int(cinfo.output_scanline) - clip.y(); + if (y >= clip.height()) + break; // We've read the entire clip region, so abort. + + (void) jpeg_read_scanlines(&cinfo, rows, 1); + + if (y < 0) + continue; // Haven't reached the starting line yet. + if (cinfo.output_components == 3) { - uchar *in = inData; - QRgb *out = (QRgb*)outData + outputLine * out_bpl; - for (uint i=0; i<cinfo.output_width; i++) { -// ### Only scaling down an image works, I don't think scaling up will work at the moment -// ### An idea I have to make this a smooth scale is to progressively add the pixel values up -// When scaling down, multiple values are being over drawn in to the output buffer. -// Instead, a weighting based on the distance the line or pixel is from the output pixel determines -// the weight of it when added to the output buffer. At present it is a non-smooth scale which is -// inefficently implemented, it still uncompresses all the jpeg, an optimization for progressive -// jpegs could be made if scaling by say 50% or some other special cases - out[sWidth * i / cinfo.output_width] = qRgb(in[0], in[1], in[2]); + // Expand 24->32 bpp. + uchar *in = rows[0] + clip.x() * 3; + QRgb *out = (QRgb*)outImage->scanLine(y); + for (int i = 0; i < clip.width(); ++i) { + *out++ = qRgb(in[0], in[1], in[2]); in += 3; } - } else { -// ### Need to test the case where the jpeg is grayscale, need some black and white jpegs to test -// this code. (also only scales down and probably won't scale to a larger size) - uchar *in = inData; - uchar *out = outData + outputLine*out_bpl; - for (uint i=0; i<cinfo.output_width; i++) { - out[sWidth * i / cinfo.output_width] = in[i]; + } else if (cinfo.out_color_space == JCS_CMYK) { + // Convert CMYK->RGB. + uchar *in = rows[0] + clip.x() * 4; + QRgb *out = (QRgb*)outImage->scanLine(y); + for (int i = 0; i < clip.width(); ++i) { + int k = in[3]; + *out++ = qRgb(k * in[0] / 255, k * in[1] / 255, + k * in[2] / 255); + in += 4; } + } else if (cinfo.output_components == 1) { + // Grayscale. + memcpy(outImage->scanLine(y), + rows[0] + clip.x(), clip.width()); } } - (void) jpeg_finish_decompress(&cinfo); - } -#ifndef QT_NO_IMAGE_SMOOTHSCALE - } else if (scaledSize.isValid() && scaledSize != QSize(cinfo.output_width, cinfo.output_height) - && quality >= HIGH_QUALITY_THRESHOLD) { - - jpegSmoothScaler scaler(&cinfo, QString().sprintf("Scale( %d, %d, ScaleFree )", - scaledSize.width(), - scaledSize.height()).toLatin1().data()); - *outImage = scaler.scale(); -#endif - } else { - if (!ensureValidImage(outImage, &cinfo)) - longjmp(jerr.setjmp_buffer, 1); - - uchar* data = outImage->bits(); - int bpl = outImage->bytesPerLine(); - while (cinfo.output_scanline < cinfo.output_height) { - uchar *d = data + cinfo.output_scanline * bpl; - (void) jpeg_read_scanlines(&cinfo, - &d, - 1); + } else { + // Load unclipped grayscale data directly into the QImage. + (void) jpeg_start_decompress(&cinfo); + while (cinfo.output_scanline < cinfo.output_height) { + uchar *row = outImage->scanLine(cinfo.output_scanline); + (void) jpeg_read_scanlines(&cinfo, &row, 1); + } } - (void) jpeg_finish_decompress(&cinfo); - if (cinfo.output_components == 3) { - // Expand 24->32 bpp. - for (uint j=0; j<cinfo.output_height; j++) { - uchar *in = outImage->scanLine(j) + cinfo.output_width * 3; - QRgb *out = (QRgb*)outImage->scanLine(j); + if (cinfo.output_scanline == cinfo.output_height) + (void) jpeg_finish_decompress(&cinfo); - for (uint i=cinfo.output_width; i--;) { - in-=3; - out[i] = qRgb(in[0], in[1], in[2]); - } - } - } else if (cinfo.out_color_space == JCS_CMYK) { - for (uint j = 0; j < cinfo.output_height; ++j) { - uchar *in = outImage->scanLine(j) + cinfo.output_width * 4; - QRgb *out = (QRgb*)outImage->scanLine(j); - - for (uint i = cinfo.output_width; i--; ) { - in-=4; - int k = in[3]; - out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255); - } - } - } if (cinfo.density_unit == 1) { outImage->setDotsPerMeterX(int(100. * cinfo.X_density / 2.54)); outImage->setDotsPerMeterY(int(100. * cinfo.Y_density / 2.54)); @@ -960,13 +929,15 @@ static bool read_jpeg_image(QIODevice *device, QImage *outImage, outImage->setDotsPerMeterY(int(100. * cinfo.Y_density)); } - if (scaledSize.isValid() && scaledSize != QSize(cinfo.output_width, cinfo.output_height)) + if (scaledSize.isValid() && scaledSize != clip.size()) *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::FastTransformation); } } jpeg_destroy_decompress(&cinfo); delete iod_src; + if (!scaledClipRect.isEmpty()) + *outImage = outImage->copy(scaledClipRect); return !outImage->isNull(); } @@ -1224,7 +1195,7 @@ bool QJpegHandler::read(QImage *image) { if (!canRead()) return false; - return read_jpeg_image(device(), image, parameters, scaledSize, quality); + return read_jpeg_image(device(), image, scaledSize, scaledClipRect, clipRect, quality); } bool QJpegHandler::write(const QImage &image) @@ -1235,9 +1206,9 @@ bool QJpegHandler::write(const QImage &image) bool QJpegHandler::supportsOption(ImageOption option) const { return option == Quality -#ifndef QT_NO_IMAGE_SMOOTHSCALE || option == ScaledSize -#endif + || option == ScaledClipRect + || option == ClipRect || option == Size || option == ImageFormat; } @@ -1246,10 +1217,12 @@ QVariant QJpegHandler::option(ImageOption option) const { if (option == Quality) { return quality; -#ifndef QT_NO_IMAGE_SMOOTHSCALE } else if (option == ScaledSize) { return scaledSize; -#endif + } else if (option == ScaledClipRect) { + return scaledClipRect; + } else if (option == ClipRect) { + return clipRect; } else if (option == Size) { if (canRead() && !device()->isSequential()) { qint64 pos = device()->pos(); @@ -1276,10 +1249,12 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value) { if (option == Quality) quality = value.toInt(); -#ifndef QT_NO_IMAGE_SMOOTHSCALE else if ( option == ScaledSize ) scaledSize = value.toSize(); -#endif + else if ( option == ScaledClipRect ) + scaledClipRect = value.toRect(); + else if ( option == ClipRect ) + clipRect = value.toRect(); } QByteArray QJpegHandler::name() const diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.h b/src/plugins/imageformats/jpeg/qjpeghandler.h index 654c078..6870cd6 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.h +++ b/src/plugins/imageformats/jpeg/qjpeghandler.h @@ -44,6 +44,7 @@ #include <QtGui/qimageiohandler.h> #include <QtCore/QSize> +#include <QtCore/QRect> QT_BEGIN_NAMESPACE @@ -66,8 +67,9 @@ public: private: int quality; - QByteArray parameters; QSize scaledSize; + QRect scaledClipRect; + QRect clipRect; }; QT_END_NAMESPACE diff --git a/src/plugins/imageformats/tiff/qtiffhandler.cpp b/src/plugins/imageformats/tiff/qtiffhandler.cpp index 9538745..7ac9722 100644 --- a/src/plugins/imageformats/tiff/qtiffhandler.cpp +++ b/src/plugins/imageformats/tiff/qtiffhandler.cpp @@ -192,11 +192,10 @@ bool QTiffHandler::read(QImage *image) return false; } + // BitsPerSample defaults to 1 according to the TIFF spec. uint16 bitPerSample; - if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample)) { - TIFFClose(tiff); - return false; - } + if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample)) + bitPerSample = 1; bool grayscale = photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE; if (grayscale && bitPerSample == 1) { diff --git a/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pro b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pro index 9687908..691cce1 100644 --- a/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pro +++ b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pro @@ -3,7 +3,7 @@ TEMPLATE = subdirs # We just want to export the sqlite3 binaries for Symbian for platforms that do not have them. symbian { - !exists($${EPOCROOT}epoc32/release/armv5/lib/sqlite3.dso) { + !symbian_no_export_sqlite:!exists($${EPOCROOT}epoc32/release/armv5/lib/sqlite3.dso) { BLD_INF_RULES.prj_exports += ":zip SQLite3_v9.2.zip" } } diff --git a/src/s60installs/bwins/QtCoreu.def b/src/s60installs/bwins/QtCoreu.def index 49c4361..fe752c8 100644 --- a/src/s60installs/bwins/QtCoreu.def +++ b/src/s60installs/bwins/QtCoreu.def @@ -2264,7 +2264,7 @@ EXPORTS ?isSequential@QIODevice@@UBE_NXZ @ 2263 NONAME ; bool QIODevice::isSequential(void) const ?isSequential@QIODevicePrivate@@QBE_NXZ @ 2264 NONAME ; bool QIODevicePrivate::isSequential(void) const ?isSequential@QProcess@@UBE_NXZ @ 2265 NONAME ; bool QProcess::isSequential(void) const - ?isSignalConnected@QObjectPrivate@@QBE_NH@Z @ 2266 NONAME ; bool QObjectPrivate::isSignalConnected(int) const + ?isSignalConnected@QObjectPrivate@@QBE_NI@Z @ 2266 NONAME ; bool QObjectPrivate::isSignalConnected(unsigned int) const ?isSimpleText@QString@@QBE_NXZ @ 2267 NONAME ; bool QString::isSimpleText(void) const ?isSingleShot@QTimer@@QBE_NXZ @ 2268 NONAME ; bool QTimer::isSingleShot(void) const ?isSpace@QChar@@QBE_NXZ @ 2269 NONAME ; bool QChar::isSpace(void) const diff --git a/src/s60installs/bwins/QtGuiu.def b/src/s60installs/bwins/QtGuiu.def index 60df1f5..7a629d7 100644 --- a/src/s60installs/bwins/QtGuiu.def +++ b/src/s60installs/bwins/QtGuiu.def @@ -2503,7 +2503,7 @@ EXPORTS ?cacheMode@QMovie@@QAE?AW4CacheMode@1@XZ @ 2502 NONAME ; enum QMovie::CacheMode QMovie::cacheMode(void) ?cacheMode@QMovie@@QBE?AW4CacheMode@1@XZ @ 2503 NONAME ; enum QMovie::CacheMode QMovie::cacheMode(void) const ?cacheStatistics@QFont@@SAXXZ @ 2504 NONAME ; void QFont::cacheStatistics(void) - ?cacheType@QTextureGlyphCache@@QBE?AW4Type@QFontEngineGlyphCache@@XZ @ 2505 NONAME ; enum QFontEngineGlyphCache::Type QTextureGlyphCache::cacheType(void) const + ?cacheType@QTextureGlyphCache@@QBE?AW4Type@QFontEngineGlyphCache@@XZ @ 2505 NONAME ABSENT ; enum QFontEngineGlyphCache::Type QTextureGlyphCache::cacheType(void) const ?calcEffectiveOpacity@QGraphicsItemPrivate@@QBEMXZ @ 2506 NONAME ; float QGraphicsItemPrivate::calcEffectiveOpacity(void) const ?calculateTabWidth@QTextEngine@@QBE?AUQFixed@@HU2@@Z @ 2507 NONAME ; struct QFixed QTextEngine::calculateTabWidth(int, struct QFixed) const ?calendarPopup@QDateTimeEdit@@QBE_NXZ @ 2508 NONAME ; bool QDateTimeEdit::calendarPopup(void) const @@ -4299,7 +4299,7 @@ EXPORTS ?expandingDirections@QSpacerItem@@UBE?AV?$QFlags@W4Orientation@Qt@@@@XZ @ 4298 NONAME ; class QFlags<enum Qt::Orientation> QSpacerItem::expandingDirections(void) const ?expandingDirections@QWidgetItem@@UBE?AV?$QFlags@W4Orientation@Qt@@@@XZ @ 4299 NONAME ; class QFlags<enum Qt::Orientation> QWidgetItem::expandingDirections(void) const ?expandsOnDoubleClick@QTreeView@@QBE_NXZ @ 4300 NONAME ; bool QTreeView::expandsOnDoubleClick(void) const - ?expireGlyphCache@QFontEngine@@AAEXXZ @ 4301 NONAME ; void QFontEngine::expireGlyphCache(void) + ?expireGlyphCache@QFontEngine@@AAEXXZ @ 4301 NONAME ABSENT ; void QFontEngine::expireGlyphCache(void) ?extension@QDialog@@QBEPAVQWidget@@XZ @ 4302 NONAME ; class QWidget * QDialog::extension(void) const ?extension@QGraphicsEllipseItem@@MBE?AVQVariant@@ABV2@@Z @ 4303 NONAME ; class QVariant QGraphicsEllipseItem::extension(class QVariant const &) const ?extension@QGraphicsItem@@MBE?AVQVariant@@ABV2@@Z @ 4304 NONAME ; class QVariant QGraphicsItem::extension(class QVariant const &) const @@ -4933,8 +4933,8 @@ EXPORTS ?globalY@QMouseEvent@@QBEHXZ @ 4932 NONAME ; int QMouseEvent::globalY(void) const ?globalY@QTabletEvent@@QBEHXZ @ 4933 NONAME ; int QTabletEvent::globalY(void) const ?globalY@QWheelEvent@@QBEHXZ @ 4934 NONAME ; int QWheelEvent::globalY(void) const - ?glyphCache@QFontEngine@@QBEPAVQFontEngineGlyphCache@@PAXABVQTransform@@@Z @ 4935 NONAME ; class QFontEngineGlyphCache * QFontEngine::glyphCache(void *, class QTransform const &) const - ?glyphCache@QFontEngine@@QBEPAVQFontEngineGlyphCache@@W4Type@2@ABVQTransform@@@Z @ 4936 NONAME ; class QFontEngineGlyphCache * QFontEngine::glyphCache(enum QFontEngineGlyphCache::Type, class QTransform const &) const + ?glyphCache@QFontEngine@@QBEPAVQFontEngineGlyphCache@@PAXABVQTransform@@@Z @ 4935 NONAME ABSENT ; class QFontEngineGlyphCache * QFontEngine::glyphCache(void *, class QTransform const &) const + ?glyphCache@QFontEngine@@QBEPAVQFontEngineGlyphCache@@W4Type@2@ABVQTransform@@@Z @ 4936 NONAME ABSENT ; class QFontEngineGlyphCache * QFontEngine::glyphCache(enum QFontEngineGlyphCache::Type, class QTransform const &) const ?glyphCount@QFontEngine@@UBEHXZ @ 4937 NONAME ; int QFontEngine::glyphCount(void) const ?glyphMargin@QTextureGlyphCache@@UBEHXZ @ 4938 NONAME ; int QTextureGlyphCache::glyphMargin(void) const ?gotFocus@QFocusEvent@@QBE_NXZ @ 4939 NONAME ; bool QFocusEvent::gotFocus(void) const @@ -9103,7 +9103,7 @@ EXPORTS ?setGestureCancelPolicy@QGesture@@QAEXW4GestureCancelPolicy@1@@Z @ 9102 NONAME ; void QGesture::setGestureCancelPolicy(enum QGesture::GestureCancelPolicy) ?setGlobalStrut@QApplication@@SAXABVQSize@@@Z @ 9103 NONAME ; void QApplication::setGlobalStrut(class QSize const &) ?setGlyphCache@QFontEngine@@QAEXPAXPAVQFontEngineGlyphCache@@@Z @ 9104 NONAME ; void QFontEngine::setGlyphCache(void *, class QFontEngineGlyphCache *) - ?setGlyphCache@QFontEngine@@QAEXW4Type@QFontEngineGlyphCache@@PAV3@@Z @ 9105 NONAME ; void QFontEngine::setGlyphCache(enum QFontEngineGlyphCache::Type, class QFontEngineGlyphCache *) + ?setGlyphCache@QFontEngine@@QAEXW4Type@QFontEngineGlyphCache@@PAV3@@Z @ 9105 NONAME ABSENT ; void QFontEngine::setGlyphCache(enum QFontEngineGlyphCache::Type, class QFontEngineGlyphCache *) ?setGraphicsEffect@QGraphicsItem@@QAEXPAVQGraphicsEffect@@@Z @ 9106 NONAME ; void QGraphicsItem::setGraphicsEffect(class QGraphicsEffect *) ?setGraphicsEffect@QWidget@@QAEXPAVQGraphicsEffect@@@Z @ 9107 NONAME ; void QWidget::setGraphicsEffect(class QGraphicsEffect *) ?setGraphicsEffectSource@QGraphicsEffectPrivate@@QAEXPAVQGraphicsEffectSource@@@Z @ 9108 NONAME ; void QGraphicsEffectPrivate::setGraphicsEffectSource(class QGraphicsEffectSource *) @@ -12517,9 +12517,12 @@ EXPORTS ?effectiveFocusWidget@QWidgetPrivate@@QAEPAVQWidget@@XZ @ 12516 NONAME ; class QWidget * QWidgetPrivate::effectiveFocusWidget(void) ?ignoreUnusedNavigationEvents@QTextControl@@QBE_NXZ @ 12517 NONAME ; bool QTextControl::ignoreUnusedNavigationEvents(void) const ?setIgnoreUnusedNavigationEvents@QTextControl@@QAEX_N@Z @ 12518 NONAME ; void QTextControl::setIgnoreUnusedNavigationEvents(bool) - ?discardUpdateRequest@QGraphicsItemPrivate@@QBE_N_N00@Z @ 12519 NONAME ; bool QGraphicsItemPrivate::discardUpdateRequest(bool, bool, bool) const - ??1QImagePixmapCleanupHooks@@QAE@XZ @ 12520 NONAME ; QImagePixmapCleanupHooks::~QImagePixmapCleanupHooks(void) + ??1QImagePixmapCleanupHooks@@QAE@XZ @ 12519 NONAME ; QImagePixmapCleanupHooks::~QImagePixmapCleanupHooks(void) + ??1QVectorPath@@QAE@XZ @ 12520 NONAME ; QVectorPath::~QVectorPath(void) ?addCacheData@QVectorPath@@QBEPAUCacheEntry@1@PAVQPaintEngineEx@@PAXP6AX01@Z@Z @ 12521 NONAME ; struct QVectorPath::CacheEntry * QVectorPath::addCacheData(class QPaintEngineEx *, void *, void (*)(class QPaintEngineEx *, void *)) const - ?makeCacheable@QVectorPath@@QBEXXZ @ 12522 NONAME ; void QVectorPath::makeCacheable(void) const - ??1QVectorPath@@QAE@XZ @ 12523 NONAME ; QVectorPath::~QVectorPath(void) + ?discardUpdateRequest@QGraphicsItemPrivate@@QBE_N_N00@Z @ 12522 NONAME ; bool QGraphicsItemPrivate::discardUpdateRequest(bool, bool, bool) const + ?makeCacheable@QVectorPath@@QBEXXZ @ 12523 NONAME ; void QVectorPath::makeCacheable(void) const + ??0Tab@QTextOption@@QAE@ABU01@@Z @ 12524 NONAME ; QTextOption::Tab::Tab(struct QTextOption::Tab const &) + ?effectiveBoundingRect@QGraphicsItemPrivate@@QBE?AVQRectF@@ABV2@@Z @ 12525 NONAME ; class QRectF QGraphicsItemPrivate::effectiveBoundingRect(class QRectF const &) const + ?glyphCache@QFontEngine@@QBEPAVQFontEngineGlyphCache@@PAXW4Type@2@ABVQTransform@@@Z @ 12526 NONAME ; class QFontEngineGlyphCache * QFontEngine::glyphCache(void *, enum QFontEngineGlyphCache::Type, class QTransform const &) const diff --git a/src/s60installs/eabi/QtGuiu.def b/src/s60installs/eabi/QtGuiu.def index 429ca79..b6862e5 100644 --- a/src/s60installs/eabi/QtGuiu.def +++ b/src/s60installs/eabi/QtGuiu.def @@ -698,13 +698,13 @@ EXPORTS _ZN11QFontDialogD2Ev @ 697 NONAME _ZN11QFontEngine11boundingBoxEjRK10QTransform @ 698 NONAME _ZN11QFontEngine11grayPaletteEv @ 699 NONAME - _ZN11QFontEngine13setGlyphCacheEN21QFontEngineGlyphCache4TypeEPS0_ @ 700 NONAME + _ZN11QFontEngine13setGlyphCacheEN21QFontEngineGlyphCache4TypeEPS0_ @ 700 NONAME ABSENT _ZN11QFontEngine13setGlyphCacheEPvP21QFontEngineGlyphCache @ 701 NONAME _ZN11QFontEngine15addGlyphsToPathEPjP11QFixedPointiP12QPainterPath6QFlagsIN9QTextItem10RenderFlagEE @ 702 NONAME _ZN11QFontEngine16addOutlineToPathEffRK12QGlyphLayoutP12QPainterPath6QFlagsIN9QTextItem10RenderFlagEE @ 703 NONAME _ZN11QFontEngine16alphaMapForGlyphEj @ 704 NONAME _ZN11QFontEngine16alphaMapForGlyphEjRK10QTransform @ 705 NONAME - _ZN11QFontEngine16expireGlyphCacheEv @ 706 NONAME + _ZN11QFontEngine16expireGlyphCacheEv @ 706 NONAME ABSENT _ZN11QFontEngine16getUnscaledGlyphEjP12QPainterPathP15glyph_metrics_t @ 707 NONAME _ZN11QFontEngine16loadKerningPairsE6QFixed @ 708 NONAME _ZN11QFontEngine16tightBoundingBoxERK12QGlyphLayout @ 709 NONAME @@ -7615,8 +7615,8 @@ EXPORTS _ZNK11QFontDialog11currentFontEv @ 7614 NONAME _ZNK11QFontDialog12selectedFontEv @ 7615 NONAME _ZNK11QFontDialog7optionsEv @ 7616 NONAME - _ZNK11QFontEngine10glyphCacheEN21QFontEngineGlyphCache4TypeERK10QTransform @ 7617 NONAME - _ZNK11QFontEngine10glyphCacheEPvRK10QTransform @ 7618 NONAME + _ZNK11QFontEngine10glyphCacheEN21QFontEngineGlyphCache4TypeERK10QTransform @ 7617 NONAME ABSENT + _ZNK11QFontEngine10glyphCacheEPvRK10QTransform @ 7618 NONAME ABSENT _ZNK11QFontEngine10glyphCountEv @ 7619 NONAME _ZNK11QFontEngine10propertiesEv @ 7620 NONAME _ZNK11QFontEngine12getSfntTableEj @ 7621 NONAME @@ -11741,4 +11741,47 @@ EXPORTS _ZN11QVectorPathD2Ev @ 11740 NONAME _ZNK11QVectorPath12addCacheDataEP14QPaintEngineExPvPFvS1_S2_E @ 11741 NONAME _ZNK20QGraphicsItemPrivate20discardUpdateRequestEbbb @ 11742 NONAME + _ZN11QEglContext10extensionsEv @ 11743 NONAME ABSENT + _ZN11QEglContext10getDisplayEP12QPaintDevice @ 11744 NONAME ABSENT + _ZN11QEglContext10waitClientEv @ 11745 NONAME ABSENT + _ZN11QEglContext10waitNativeEv @ 11746 NONAME ABSENT + _ZN11QEglContext11doneCurrentEv @ 11747 NONAME ABSENT + _ZN11QEglContext11errorStringEi @ 11748 NONAME ABSENT + _ZN11QEglContext11makeCurrentEi @ 11749 NONAME ABSENT + _ZN11QEglContext11openDisplayEP12QPaintDevice @ 11750 NONAME ABSENT + _ZN11QEglContext11swapBuffersEi @ 11751 NONAME ABSENT + _ZN11QEglContext12chooseConfigERK14QEglPropertiesN4QEgl16PixelFormatMatchE @ 11752 NONAME ABSENT + _ZN11QEglContext12hasExtensionEPKc @ 11753 NONAME ABSENT + _ZN11QEglContext13createContextEPS_PK14QEglProperties @ 11754 NONAME ABSENT + _ZN11QEglContext13createSurfaceEP12QPaintDevicePK14QEglProperties @ 11755 NONAME ABSENT + _ZN11QEglContext14currentContextEN4QEgl3APIE @ 11756 NONAME ABSENT + _ZN11QEglContext14defaultDisplayEP12QPaintDevice @ 11757 NONAME ABSENT + _ZN11QEglContext14destroySurfaceEi @ 11758 NONAME ABSENT + _ZN11QEglContext14dumpAllConfigsEv @ 11759 NONAME ABSENT + _ZN11QEglContext15lazyDoneCurrentEv @ 11760 NONAME ABSENT + _ZN11QEglContext17setCurrentContextEN4QEgl3APIEPS_ @ 11761 NONAME ABSENT + _ZN11QEglContext7destroyEv @ 11762 NONAME ABSENT + _ZN11QEglContextC1Ev @ 11763 NONAME ABSENT + _ZN11QEglContextC2Ev @ 11764 NONAME ABSENT + _ZN11QEglContextD1Ev @ 11765 NONAME ABSENT + _ZN11QEglContextD2Ev @ 11766 NONAME ABSENT + _ZN14QEglProperties11removeValueEi @ 11767 NONAME ABSENT + _ZN14QEglProperties14dumpAllConfigsEv @ 11768 NONAME ABSENT + _ZN14QEglProperties14setPixelFormatEN6QImage6FormatE @ 11769 NONAME ABSENT + _ZN14QEglProperties17setRenderableTypeEN4QEgl3APIE @ 11770 NONAME ABSENT + _ZN14QEglProperties19reduceConfigurationEv @ 11771 NONAME ABSENT + _ZN14QEglProperties20setPaintDeviceFormatEP12QPaintDevice @ 11772 NONAME ABSENT + _ZN14QEglProperties8setValueEii @ 11773 NONAME ABSENT + _ZN14QEglPropertiesC1Ei @ 11774 NONAME ABSENT + _ZN14QEglPropertiesC1Ev @ 11775 NONAME ABSENT + _ZN14QEglPropertiesC2Ei @ 11776 NONAME ABSENT + _ZN14QEglPropertiesC2Ev @ 11777 NONAME ABSENT + _ZNK11QEglContext12configAttribEiPi @ 11778 NONAME ABSENT + _ZNK11QEglContext16configPropertiesEi @ 11779 NONAME ABSENT + _ZNK11QEglContext7isValidEv @ 11780 NONAME ABSENT + _ZNK11QEglContext9isCurrentEv @ 11781 NONAME ABSENT + _ZNK14QEglProperties5valueEi @ 11782 NONAME ABSENT + _ZNK14QEglProperties8toStringEv @ 11783 NONAME ABSENT + _ZNK11QFontEngine10glyphCacheEPvN21QFontEngineGlyphCache4TypeERK10QTransform @ 11784 NONAME + _ZNK20QGraphicsItemPrivate21effectiveBoundingRectERK6QRectF @ 11785 NONAME diff --git a/src/s60installs/eabi/QtOpenVGu.def b/src/s60installs/eabi/QtOpenVGu.def index 8458983..7526632 100644 --- a/src/s60installs/eabi/QtOpenVGu.def +++ b/src/s60installs/eabi/QtOpenVGu.def @@ -1,8 +1,8 @@ EXPORTS _Z16qPixmapToVGImageRK7QPixmap @ 1 NONAME - _Z20qt_vg_create_contextP12QPaintDevice @ 2 NONAME + _Z20qt_vg_create_contextP12QPaintDevice @ 2 NONAME ABSENT _Z20qt_vg_shared_surfacev @ 3 NONAME - _Z21qt_vg_destroy_contextP11QEglContext @ 4 NONAME + _Z21qt_vg_destroy_contextP11QEglContext @ 4 NONAME ABSENT _Z24qt_vg_image_to_vg_formatN6QImage6FormatE @ 5 NONAME _Z25qt_vg_config_to_vg_formatP11QEglContext @ 6 NONAME _Z25qt_vg_create_paint_enginev @ 7 NONAME @@ -169,4 +169,8 @@ EXPORTS _ZThn8_NK16QVGWindowSurface6metricEN12QPaintDevice17PaintDeviceMetricE @ 168 NONAME _ZN14QVGPaintEngine10fillRegionERK7QRegionRK6QColorRK5QSize @ 169 NONAME _ZN20QVGCompositionHelper10blitWindowEmRK5QSizeRK5QRectRK6QPointi @ 170 NONAME + _Z20qt_vg_create_contextP12QPaintDevicei @ 171 NONAME + _Z21qt_vg_destroy_contextP11QEglContexti @ 172 NONAME + _ZN13QVGPixmapData22destroyImageAndContextEv @ 173 NONAME + _ZN13QVGPixmapData9hibernateEv @ 174 NONAME diff --git a/src/s60installs/qt.iby b/src/s60installs/qt.iby index 41eb562..f24ac4b 100644 --- a/src/s60installs/qt.iby +++ b/src/s60installs/qt.iby @@ -90,27 +90,27 @@ file=ABI_DIR\BUILD_DIR\qts60plugin_5_0.dll SHARED_LIB_DIR\qts60plugin_5_0.dll S60_APP_RESOURCE(s60main) // imageformats stubs -data=\epoc32\winscw\c\resource\qt\plugins\imageformats\qgif.qtplugin resource\qt\plugins\imageformats\qgif.qtplugin -data=\epoc32\winscw\c\resource\qt\plugins\imageformats\qico.qtplugin resource\qt\plugins\imageformats\qico.qtplugin -data=\epoc32\winscw\c\resource\qt\plugins\imageformats\qjpeg.qtplugin resource\qt\plugins\imageformats\qjpeg.qtplugin -data=\epoc32\winscw\c\resource\qt\plugins\imageformats\qmng.qtplugin resource\qt\plugins\imageformats\qmng.qtplugin -data=\epoc32\winscw\c\resource\qt\plugins\imageformats\qsvg.qtplugin resource\qt\plugins\imageformats\qsvg.qtplugin -data=\epoc32\winscw\c\resource\qt\plugins\imageformats\qtiff.qtplugin resource\qt\plugins\imageformats\qtiff.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\qgif.qtplugin resource\qt\plugins\imageformats\qgif.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\qico.qtplugin resource\qt\plugins\imageformats\qico.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\qjpeg.qtplugin resource\qt\plugins\imageformats\qjpeg.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\qmng.qtplugin resource\qt\plugins\imageformats\qmng.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\qsvg.qtplugin resource\qt\plugins\imageformats\qsvg.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\qtiff.qtplugin resource\qt\plugins\imageformats\qtiff.qtplugin // codecs stubs -data=\epoc32\winscw\c\resource\qt\plugins\codecs\qcncodecs.qtplugin resource\qt\plugins\codecs\qcncodecs.qtplugin -data=\epoc32\winscw\c\resource\qt\plugins\codecs\qjpcodecs.qtplugin resource\qt\plugins\codecs\qjpcodecs.qtplugin -data=\epoc32\winscw\c\resource\qt\plugins\codecs\qkrcodecs.qtplugin resource\qt\plugins\codecs\qkrcodecs.qtplugin -data=\epoc32\winscw\c\resource\qt\plugins\codecs\qtwcodecs.qtplugin resource\qt\plugins\codecs\qtwcodecs.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\qcncodecs.qtplugin resource\qt\plugins\codecs\qcncodecs.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\qjpcodecs.qtplugin resource\qt\plugins\codecs\qjpcodecs.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\qkrcodecs.qtplugin resource\qt\plugins\codecs\qkrcodecs.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\qtwcodecs.qtplugin resource\qt\plugins\codecs\qtwcodecs.qtplugin // iconengines stubs -data=\epoc32\winscw\c\resource\qt\plugins\iconengines\qsvgicon.qtplugin resource\qt\plugins\iconengines\qsvgicon.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\qsvgicon.qtplugin resource\qt\plugins\iconengines\qsvgicon.qtplugin // Phonon MMF backend -data=\epoc32\winscw\c\resource\qt\plugins\phonon_backend\phonon_mmf.qtplugin resource\qt\plugins\phonon_backend\phonon_mmf.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\phonon_mmf.qtplugin resource\qt\plugins\phonon_backend\phonon_mmf.qtplugin // graphicssystems -data=\epoc32\winscw\c\resource\qt\plugins\graphicssystems\qvggraphicssystem.qtplugin resource\qt\plugins\graphicssystems\qvggraphicssystem.qtplugin +data=\epoc32\data\qt\qtlibspluginstubs\qvggraphicssystem.qtplugin resource\qt\plugins\graphicssystems\qvggraphicssystem.qtplugin // Stub sis file data=ZSYSTEM\install\qt.sis System\Install\qt.sis diff --git a/src/s60installs/s60installs.pro b/src/s60installs/s60installs.pro index 37adfa9..e024396 100644 --- a/src/s60installs/s60installs.pro +++ b/src/s60installs/s60installs.pro @@ -105,10 +105,6 @@ symbian: { qtlibraries.sources += QtDeclarative.dll } - contains(QT_CONFIG, webkit): { - qtlibraries.sources += QtWebKit.dll - } - graphicssystems_plugins.path = c:$$QT_PLUGINS_BASE_DIR/graphicssystems contains(QT_CONFIG, openvg) { qtlibraries.sources += QtOpenVG.dll @@ -117,4 +113,9 @@ symbian: { BLD_INF_RULES.prj_exports += "qt.iby $$CORE_MW_LAYER_IBY_EXPORT_PATH(qt.iby)" BLD_INF_RULES.prj_exports += "qtdemoapps.iby $$CORE_APP_LAYER_IBY_EXPORT_PATH(qtdemoapps.iby)" + PLUGIN_STUBS = $$files(qmakepluginstubs/*) + for(STUB, PLUGIN_STUBS) { + STUB_FILENAME = $$basename(STUB) + BLD_INF_RULES.prj_exports += "qmakepluginstubs/$${STUB_FILENAME} /epoc32/data/qt/qtlibspluginstubs/$${STUB_FILENAME}" + } } diff --git a/src/s60main/qts60main.cpp b/src/s60main/qts60main.cpp index 725b17c..de7d0be 100644 --- a/src/s60main/qts60main.cpp +++ b/src/s60main/qts60main.cpp @@ -6,35 +6,34 @@ ** ** This file is part of the Symbian application wrapper of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -54,7 +53,7 @@ GLDEF_C TInt E32Main() { CTrapCleanup *cleanupStack = q_check_ptr(CTrapCleanup::New()); TInt err = 0; - TRAP(err, QtMainWrapper()); + TRAP(err, err = QtMainWrapper()); delete cleanupStack; return err; diff --git a/src/s60main/qts60main_mcrt0.cpp b/src/s60main/qts60main_mcrt0.cpp index edc2fb8..18c09e5 100644 --- a/src/s60main/qts60main_mcrt0.cpp +++ b/src/s60main/qts60main_mcrt0.cpp @@ -6,35 +6,34 @@ ** ** This file is part of the Symbian application wrapper of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: ** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. ** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/script/bridge/qscriptobject.cpp b/src/script/bridge/qscriptobject.cpp index 2d71c43..6942eb6 100644 --- a/src/script/bridge/qscriptobject.cpp +++ b/src/script/bridge/qscriptobject.cpp @@ -61,6 +61,15 @@ bool QScriptObject::getOwnPropertySlot(JSC::ExecState* exec, return d->delegate->getOwnPropertySlot(this, exec, propertyName, slot); } +bool QScriptObject::getOwnPropertyDescriptor(JSC::ExecState* exec, + const JSC::Identifier& propertyName, + JSC::PropertyDescriptor& descriptor) +{ + if (!d || !d->delegate) + return JSC::JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor); + return d->delegate->getOwnPropertyDescriptor(this, exec, propertyName, descriptor); +} + void QScriptObject::put(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::JSValue value, JSC::PutPropertySlot& slot) { @@ -164,6 +173,14 @@ bool QScriptObjectDelegate::getOwnPropertySlot(QScriptObject* object, JSC::ExecS return object->JSC::JSObject::getOwnPropertySlot(exec, propertyName, slot); } +bool QScriptObjectDelegate::getOwnPropertyDescriptor(QScriptObject* object, JSC::ExecState* exec, + const JSC::Identifier& propertyName, + JSC::PropertyDescriptor& descriptor) +{ + return object->JSC::JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor); +} + + void QScriptObjectDelegate::put(QScriptObject* object, JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::JSValue value, JSC::PutPropertySlot& slot) diff --git a/src/script/bridge/qscriptobject_p.h b/src/script/bridge/qscriptobject_p.h index a4faa06..f4b7140 100644 --- a/src/script/bridge/qscriptobject_p.h +++ b/src/script/bridge/qscriptobject_p.h @@ -63,6 +63,7 @@ public: virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&); + virtual bool getOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&); virtual void put(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&); virtual bool deleteProperty(JSC::ExecState*, @@ -121,6 +122,9 @@ public: virtual bool getOwnPropertySlot(QScriptObject*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&); + virtual bool getOwnPropertyDescriptor(QScriptObject*, JSC::ExecState*, + const JSC::Identifier& propertyName, + JSC::PropertyDescriptor&); virtual void put(QScriptObject*, JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&); virtual bool deleteProperty(QScriptObject*, JSC::ExecState*, diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp index 63ba9ec..b51cb68 100644 --- a/src/script/bridge/qscriptqobject.cpp +++ b/src/script/bridge/qscriptqobject.cpp @@ -1173,6 +1173,7 @@ bool QObjectDelegate::getOwnPropertySlot(QScriptObject *object, JSC::ExecState * const JSC::Identifier &propertyName, JSC::PropertySlot &slot) { + //Note: this has to be kept in sync with getOwnPropertyDescriptor #ifndef QT_NO_PROPERTIES QByteArray name = QString(propertyName.ustring()).toLatin1(); QObject *qobject = data->value; @@ -1285,6 +1286,142 @@ bool QObjectDelegate::getOwnPropertySlot(QScriptObject *object, JSC::ExecState * #endif //QT_NO_PROPERTIES } + +bool QObjectDelegate::getOwnPropertyDescriptor(QScriptObject *object, JSC::ExecState *exec, + const JSC::Identifier &propertyName, + JSC::PropertyDescriptor &descriptor) +{ + //Note: this has to be kept in sync with getOwnPropertySlot abd getPropertyAttributes +#ifndef QT_NO_PROPERTIES + QByteArray name = QString(propertyName.ustring()).toLatin1(); + QObject *qobject = data->value; + if (!qobject) { + QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject") + .arg(QString::fromLatin1(name)); + descriptor.setValue(JSC::throwError(exec, JSC::GeneralError, message)); + return true; + } + + const QScriptEngine::QObjectWrapOptions &opt = data->options; + + const QMetaObject *meta = qobject->metaObject(); + { + QHash<QByteArray, JSC::JSValue>::const_iterator it = data->cachedMembers.constFind(name); + if (it != data->cachedMembers.constEnd()) { + int index; + if (GeneratePropertyFunctions && ((index = meta->indexOfProperty(name)) != -1)) { + QMetaProperty prop = meta->property(index); + descriptor.setAccessorDescriptor(it.value(), it.value(), flagsForMetaProperty(prop)); + if (!prop.isWritable()) + descriptor.setWritable(false); + } else { + unsigned attributes = QObjectMemberAttribute; + if (opt & QScriptEngine::SkipMethodsInEnumeration) + attributes |= JSC::DontEnum; + descriptor.setDescriptor(it.value(), attributes); + } + return true; + } + } + + QScriptEnginePrivate *eng = scriptEngineFromExec(exec); + int index = -1; + if (name.contains('(')) { + QByteArray normalized = QMetaObject::normalizedSignature(name); + if (-1 != (index = meta->indexOfMethod(normalized))) { + QMetaMethod method = meta->method(index); + if (hasMethodAccess(method, index, opt)) { + if (!(opt & QScriptEngine::ExcludeSuperClassMethods) + || (index >= meta->methodOffset())) { + QtFunction *fun = new (exec)QtFunction( + object, index, /*maybeOverloaded=*/false, + &exec->globalData(), eng->originalGlobalObject()->functionStructure(), + propertyName); + data->cachedMembers.insert(name, fun); + unsigned attributes = QObjectMemberAttribute; + if (opt & QScriptEngine::SkipMethodsInEnumeration) + attributes |= JSC::DontEnum; + descriptor.setDescriptor(fun, attributes); + return true; + } + } + } + } + + index = meta->indexOfProperty(name); + if (index != -1) { + QMetaProperty prop = meta->property(index); + if (prop.isScriptable()) { + if (!(opt & QScriptEngine::ExcludeSuperClassProperties) + || (index >= meta->propertyOffset())) { + unsigned attributes = flagsForMetaProperty(prop); + if (GeneratePropertyFunctions) { + QtPropertyFunction *fun = new (exec)QtPropertyFunction( + meta, index, &exec->globalData(), + eng->originalGlobalObject()->functionStructure(), + propertyName); + data->cachedMembers.insert(name, fun); + descriptor.setAccessorDescriptor(fun, fun, attributes); + if (attributes & JSC::ReadOnly) + descriptor.setWritable(false); + } else { + JSC::JSValue val; + if (!prop.isValid()) + val = JSC::jsUndefined(); + else + val = eng->jscValueFromVariant(prop.read(qobject)); + descriptor.setDescriptor(val, attributes); + } + return true; + } + } + } + + index = qobject->dynamicPropertyNames().indexOf(name); + if (index != -1) { + JSC::JSValue val = eng->jscValueFromVariant(qobject->property(name)); + descriptor.setDescriptor(val, QObjectMemberAttribute); + return true; + } + + const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods) + ? meta->methodOffset() : 0; + for (index = meta->methodCount() - 1; index >= offset; --index) { + QMetaMethod method = meta->method(index); + if (hasMethodAccess(method, index, opt) + && (methodName(method) == name)) { + QtFunction *fun = new (exec)QtFunction( + object, index, /*maybeOverloaded=*/true, + &exec->globalData(), eng->originalGlobalObject()->functionStructure(), + propertyName); + unsigned attributes = QObjectMemberAttribute; + if (opt & QScriptEngine::SkipMethodsInEnumeration) + attributes |= JSC::DontEnum; + descriptor.setDescriptor(fun, attributes); + data->cachedMembers.insert(name, fun); + return true; + } + } + + if (!(opt & QScriptEngine::ExcludeChildObjects)) { + QList<QObject*> children = qobject->children(); + for (index = 0; index < children.count(); ++index) { + QObject *child = children.at(index); + if (child->objectName() == QString(propertyName.ustring())) { + QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject; + QScriptValue tmp = QScriptEnginePrivate::get(eng)->newQObject(child, QScriptEngine::QtOwnership, opt); + descriptor.setDescriptor(eng->scriptValueToJSCValue(tmp), JSC::ReadOnly | JSC::DontDelete | JSC::DontEnum); + return true; + } + } + } + + return QScriptObjectDelegate::getOwnPropertyDescriptor(object, exec, propertyName, descriptor); +#else //QT_NO_PROPERTIES + return false; +#endif //QT_NO_PROPERTIES +} + void QObjectDelegate::put(QScriptObject *object, JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::JSValue value, JSC::PutPropertySlot &slot) @@ -1437,7 +1574,7 @@ bool QObjectDelegate::getPropertyAttributes(const QScriptObject *object, unsigned &attributes) const { #ifndef QT_NO_PROPERTIES - // ### try to avoid duplicating logic from getOwnPropertySlot() + //Note: this has to be kept in sync with getOwnPropertyDescriptor and getOwnPropertySlot QByteArray name = ((QString)propertyName.ustring()).toLatin1(); QObject *qobject = data->value; if (!qobject) @@ -1688,6 +1825,7 @@ QObjectPrototype::QObjectPrototype(JSC::ExecState* exec, WTF::PassRefPtr<JSC::St putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/0, exec->propertyNames().toString, qobjectProtoFuncToString), JSC::DontEnum); putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChild"), qobjectProtoFuncFindChild), JSC::DontEnum); putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChildren"), qobjectProtoFuncFindChildren), JSC::DontEnum); + this->structure()->setHasGetterSetterProperties(true); } const JSC::ClassInfo QMetaObjectWrapperObject::info = { "QMetaObject", 0, 0, 0 }; diff --git a/src/script/bridge/qscriptqobject_p.h b/src/script/bridge/qscriptqobject_p.h index 41900b5..0e7748d 100644 --- a/src/script/bridge/qscriptqobject_p.h +++ b/src/script/bridge/qscriptqobject_p.h @@ -78,6 +78,10 @@ public: virtual bool getOwnPropertySlot(QScriptObject*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&); + virtual bool getOwnPropertyDescriptor(QScriptObject*, JSC::ExecState*, + const JSC::Identifier& propertyName, + JSC::PropertyDescriptor&); + virtual void put(QScriptObject*, JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&); diff --git a/src/sql/drivers/oci/qsql_oci.cpp b/src/sql/drivers/oci/qsql_oci.cpp index f130087..a384ba0 100644 --- a/src/sql/drivers/oci/qsql_oci.cpp +++ b/src/sql/drivers/oci/qsql_oci.cpp @@ -517,7 +517,7 @@ QVariant::Type qDecodeOCIType(const QString& ocitype, QSql::NumericalPrecisionPo } else if (ocitype == QLatin1String("LONG") || ocitype == QLatin1String("NCLOB") || ocitype == QLatin1String("CLOB")) - type = QVariant::ByteArray; + type = QVariant::String; else if (ocitype == QLatin1String("RAW") || ocitype == QLatin1String("LONG RAW") || ocitype == QLatin1String("ROWID") || ocitype == QLatin1String("BLOB") || ocitype == QLatin1String("CFILE") || ocitype == QLatin1String("BFILE")) @@ -543,6 +543,7 @@ QVariant::Type qDecodeOCIType(int ocitype, QSql::NumericalPrecisionPolicy precis case SQLT_AVC: case SQLT_RDD: case SQLT_LNG: + case SQLT_CLOB: #ifdef SQLT_INTERVAL_YM case SQLT_INTERVAL_YM: #endif @@ -584,7 +585,6 @@ QVariant::Type qDecodeOCIType(int ocitype, QSql::NumericalPrecisionPolicy precis case SQLT_NTY: case SQLT_REF: case SQLT_RID: - case SQLT_CLOB: type = QVariant::ByteArray; break; case SQLT_DAT: diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp index e686873..55f0696 100644 --- a/src/sql/drivers/odbc/qsql_odbc.cpp +++ b/src/sql/drivers/odbc/qsql_odbc.cpp @@ -172,28 +172,39 @@ static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode SQLSMALLINT msgLen = 0; SQLRETURN r = SQL_NO_DATA; SQLTCHAR state_[SQL_SQLSTATE_SIZE+1]; - SQLTCHAR description_[SQL_MAX_MESSAGE_LENGTH]; + QVarLengthArray<SQLTCHAR> description_(SQL_MAX_MESSAGE_LENGTH); QString result; int i = 1; description_[0] = 0; + r = SQLGetDiagRec(handleType, + handle, + i, + state_, + &nativeCode_, + 0, + NULL, + &msgLen); + if(r == SQL_NO_DATA) + return QString(); + description_.resize(msgLen+1); do { r = SQLGetDiagRec(handleType, handle, i, - (SQLTCHAR*)state_, + state_, &nativeCode_, - (SQLTCHAR*)description_, - SQL_MAX_MESSAGE_LENGTH, /* in bytes, not in characters */ + description_.data(), + description_.size(), &msgLen); if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) { if (nativeCode) *nativeCode = nativeCode_; QString tmpstore; #ifdef UNICODE - tmpstore = QString((const QChar*)description_, msgLen); + tmpstore = QString((const QChar*)description_.data(), msgLen); #else - tmpstore = QString::fromLocal8Bit((const char*)description_, msgLen); + tmpstore = QString::fromLocal8Bit((const char*)description_.data(), msgLen); #endif if(result != tmpstore) { if(!result.isEmpty()) @@ -877,12 +888,17 @@ bool QODBCResult::reset (const QString& query) (SQLCHAR*) query8.constData(), (SQLINTEGER) query8.length()); #endif - if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) { + if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r!= SQL_NO_DATA) { setLastError(qMakeError(QCoreApplication::translate("QODBCResult", "Unable to execute statement"), QSqlError::StatementError, d)); return false; } + if(r == SQL_NO_DATA) { + setSelect(false); + return true; + } + SQLINTEGER isScrollable, bufferLength; r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, &bufferLength); if(r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index 3ed918e..21c947b 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -1147,12 +1147,12 @@ static QMatrix parseTransformationMatrix(const QStringRef &value) if (points.count() != 1) goto error; const qreal deg2rad = qreal(0.017453292519943295769); - matrix.shear(tan(points[0]*deg2rad), 0); + matrix.shear(qTan(points[0]*deg2rad), 0); } else if (state == SkewY) { if (points.count() != 1) goto error; const qreal deg2rad = qreal(0.017453292519943295769); - matrix.shear(0, tan(points[0]*deg2rad)); + matrix.shear(0, qTan(points[0]*deg2rad)); } } error: @@ -1481,8 +1481,8 @@ static void pathArc(QPainterPath &path, yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); /* (xc, yc) is center of the circle. */ - th0 = atan2(y0 - yc, x0 - xc); - th1 = atan2(y1 - yc, x1 - xc); + th0 = qAtan2(y0 - yc, x0 - xc); + th1 = qAtan2(y1 - yc, x1 - xc); th_arc = th1 - th0; if (th_arc < 0 && sweep_flag) @@ -1578,8 +1578,8 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) count--; break; } - x = x0 = num[0] + offsetX; - y = y0 = num[1] + offsetY; + x = num[0] + offsetX; + y = num[1] + offsetY; num += 2; count -= 2; path.lineTo(x, y); @@ -1592,8 +1592,8 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) count--; break; } - x = x0 = num[0]; - y = y0 = num[1]; + x = num[0]; + y = num[1]; num += 2; count -= 2; path.lineTo(x, y); @@ -2864,14 +2864,8 @@ static QSvgNode *createPolygonNode(QSvgNode *parent, const QChar *s = pointsStr.constData(); QVector<qreal> points = parseNumbersList(s); QPolygonF poly(points.count()/2); - int i = 0; - QVector<qreal>::const_iterator itr = points.constBegin(); - while (itr != points.constEnd()) { - qreal one = *itr; ++itr; - qreal two = *itr; ++itr; - poly[i] = QPointF(one, two); - ++i; - } + for (int i = 0; i < poly.size(); ++i) + poly[i] = QPointF(points.at(2 * i), points.at(2 * i + 1)); QSvgNode *polygon = new QSvgPolygon(parent, poly); return polygon; } @@ -2886,14 +2880,8 @@ static QSvgNode *createPolylineNode(QSvgNode *parent, const QChar *s = pointsStr.constData(); QVector<qreal> points = parseNumbersList(s); QPolygonF poly(points.count()/2); - int i = 0; - QVector<qreal>::const_iterator itr = points.constBegin(); - while (itr != points.constEnd()) { - qreal one = *itr; ++itr; - qreal two = *itr; ++itr; - poly[i] = QPointF(one, two); - ++i; - } + for (int i = 0; i < poly.size(); ++i) + poly[i] = QPointF(points.at(2 * i), points.at(2 * i + 1)); QSvgNode *line = new QSvgPolyline(parent, poly); return line; diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp index 57927fd..c67f7d2 100644 --- a/src/svg/qsvgstyle.cpp +++ b/src/svg/qsvgstyle.cpp @@ -771,7 +771,7 @@ void QSvgAnimateTransform::resolveMatrix(QSvgNode *node) qreal transXDiff = (to1-from1) * percentOfAnimation; qreal transX = from1 + transXDiff; m_transform = QTransform(); - m_transform.shear(tan(transX * deg2rad), 0); + m_transform.shear(qTan(transX * deg2rad), 0); break; } case SkewY: { @@ -786,7 +786,7 @@ void QSvgAnimateTransform::resolveMatrix(QSvgNode *node) qreal transYDiff = (to1 - from1) * percentOfAnimation; qreal transY = from1 + transYDiff; m_transform = QTransform(); - m_transform.shear(0, tan(transY * deg2rad)); + m_transform.shear(0, qTan(transY * deg2rad)); break; } default: diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index 8fcc0df..1a75cf6 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -725,16 +725,6 @@ void Generator::generateMetacall() needEditable |= p.editable.endsWith(')'); needUser |= p.user.endsWith(')'); } - bool needAnything = needGet - | needSet - | needReset - | needDesignable - | needScriptable - | needStored - | needEditable - | needUser; - if (!needAnything) - goto skip_properties; fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n "); if (needElse) @@ -904,7 +894,6 @@ void Generator::generateMetacall() fprintf(out, "\n#endif // QT_NO_PROPERTIES"); } - skip_properties: if (methodList.size() || cdef->signalList.size() || cdef->propertyList.size()) fprintf(out, "\n "); fprintf(out,"return _id;\n}\n"); diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp index 88dfa98..3bc56ae 100644 --- a/src/tools/uic/cpp/cppwriteinitialization.cpp +++ b/src/tools/uic/cpp/cppwriteinitialization.cpp @@ -1221,9 +1221,10 @@ void WriteInitialization::writeProperties(const QString &varName, const DomRect *r = p->elementRect(); m_output << m_indent << varName << "->resize(" << r->elementWidth() << ", " << r->elementHeight() << ");\n"; continue; - } else if (propertyName == QLatin1String("buttonGroupId") && buttonGroupWidget) { // Q3ButtonGroup support - m_output << m_indent << m_driver->findOrInsertWidget(buttonGroupWidget) << "->insert(" - << varName << ", " << p->elementNumber() << ");\n"; + } else if (propertyName == QLatin1String("buttonGroupId")) { // Q3ButtonGroup support + if (buttonGroupWidget) + m_output << m_indent << m_driver->findOrInsertWidget(buttonGroupWidget) << "->insert(" + << varName << ", " << p->elementNumber() << ");\n"; continue; } else if (propertyName == QLatin1String("currentRow") // QListWidget::currentRow && m_uic->customWidgetsInfo()->extends(className, QLatin1String("QListWidget"))) { diff --git a/src/xml/sax/qxml.cpp b/src/xml/sax/qxml.cpp index 0a87412..27ec3bd 100644 --- a/src/xml/sax/qxml.cpp +++ b/src/xml/sax/qxml.cpp @@ -3063,11 +3063,11 @@ void QXmlSimpleReaderPrivate::initIncrementalParsing() Aspects of the parsing behavior can be adapted using setFeature() and setProperty(). + \snippet doc/src/snippets/code/src_xml_sax_qxml.cpp 0 + QXmlSimpleReader is not reentrant. If you want to use the class in threaded code, lock the code using QXmlSimpleReader with a locking mechanism, such as a QMutex. - - \snippet doc/src/snippets/code/src_xml_sax_qxml.cpp 0 */ static inline bool is_S(QChar ch) diff --git a/src/xmlpatterns/api/api.pri b/src/xmlpatterns/api/api.pri index 9fcc2f5..a0adf75 100644 --- a/src/xmlpatterns/api/api.pri +++ b/src/xmlpatterns/api/api.pri @@ -1,59 +1,57 @@ -HEADERS += $$PWD/qabstractxmlforwarditerator_p.h \ - $$PWD/qabstractmessagehandler.h \ - $$PWD/qabstracturiresolver.h \ - $$PWD/qabstractxmlnodemodel.h \ - $$PWD/qabstractxmlnodemodel_p.h \ - $$PWD/qabstractxmlpullprovider_p.h \ - $$PWD/qabstractxmlreceiver.h \ - $$PWD/qabstractxmlreceiver_p.h \ - $$PWD/qdeviceresourceloader_p.h \ - $$PWD/qiodevicedelegate_p.h \ - $$PWD/qnetworkaccessdelegator_p.h \ - $$PWD/qpullbridge_p.h \ - $$PWD/qresourcedelegator_p.h \ - $$PWD/qsimplexmlnodemodel.h \ - $$PWD/qsourcelocation.h \ - $$PWD/quriloader_p.h \ - $$PWD/qvariableloader_p.h \ - $$PWD/qxmlformatter.h \ - $$PWD/qxmlname.h \ - $$PWD/qxmlnamepool.h \ - $$PWD/qxmlquery.h \ - $$PWD/qxmlquery_p.h \ - $$PWD/qxmlresultitems.h \ - $$PWD/qxmlresultitems_p.h \ - $$PWD/qxmlschema.h \ - $$PWD/qxmlschema_p.h \ - $$PWD/qxmlschemavalidator.h \ - $$PWD/qxmlschemavalidator_p.h \ - $$PWD/qxmlserializer.h \ - $$PWD/qxmlserializer_p.h \ - $$PWD/../../../tools/xmlpatterns/qcoloringmessagehandler_p.h \ - $$PWD/../../../tools/xmlpatterns/qcoloroutput_p.h - -SOURCES += $$PWD/qvariableloader.cpp \ - $$PWD/qabstractmessagehandler.cpp \ - $$PWD/qabstracturiresolver.cpp \ - $$PWD/qabstractxmlnodemodel.cpp \ - $$PWD/qabstractxmlpullprovider.cpp \ - $$PWD/qabstractxmlreceiver.cpp \ - $$PWD/qiodevicedelegate.cpp \ - $$PWD/qnetworkaccessdelegator.cpp \ - $$PWD/qpullbridge.cpp \ - $$PWD/qresourcedelegator.cpp \ - $$PWD/qsimplexmlnodemodel.cpp \ - $$PWD/qsourcelocation.cpp \ - $$PWD/quriloader.cpp \ - $$PWD/qxmlformatter.cpp \ - $$PWD/qxmlname.cpp \ - $$PWD/qxmlnamepool.cpp \ - $$PWD/qxmlquery.cpp \ - $$PWD/qxmlresultitems.cpp \ - $$PWD/qxmlschema.cpp \ - $$PWD/qxmlschema_p.cpp \ - $$PWD/qxmlschemavalidator.cpp \ - $$PWD/qxmlserializer.cpp \ - $$PWD/../../../tools/xmlpatterns/qcoloringmessagehandler.cpp \ - $$PWD/../../../tools/xmlpatterns/qcoloroutput.cpp - -INCLUDEPATH += $$PWD/../../../tools/xmlpatterns/ +HEADERS += $$PWD/qabstractxmlforwarditerator_p.h \ + $$PWD/qabstractmessagehandler.h \ + $$PWD/qabstracturiresolver.h \ + $$PWD/qabstractxmlnodemodel.h \ + $$PWD/qabstractxmlnodemodel_p.h \ + $$PWD/qabstractxmlpullprovider_p.h \ + $$PWD/qabstractxmlreceiver.h \ + $$PWD/qabstractxmlreceiver_p.h \ + $$PWD/qdeviceresourceloader_p.h \ + $$PWD/qiodevicedelegate_p.h \ + $$PWD/qnetworkaccessdelegator_p.h \ + $$PWD/qpullbridge_p.h \ + $$PWD/qresourcedelegator_p.h \ + $$PWD/qsimplexmlnodemodel.h \ + $$PWD/qsourcelocation.h \ + $$PWD/quriloader_p.h \ + $$PWD/qvariableloader_p.h \ + $$PWD/qxmlformatter.h \ + $$PWD/qxmlname.h \ + $$PWD/qxmlnamepool.h \ + $$PWD/qxmlquery.h \ + $$PWD/qxmlquery_p.h \ + $$PWD/qxmlresultitems.h \ + $$PWD/qxmlresultitems_p.h \ + $$PWD/qxmlschema.h \ + $$PWD/qxmlschema_p.h \ + $$PWD/qxmlschemavalidator.h \ + $$PWD/qxmlschemavalidator_p.h \ + $$PWD/qxmlserializer.h \ + $$PWD/qxmlserializer_p.h \ + $$PWD/qcoloringmessagehandler_p.h \ + $$PWD/qcoloroutput_p.h \ + $$PWD/qxmlpatternistcli_p.h +SOURCES += $$PWD/qvariableloader.cpp \ + $$PWD/qabstractmessagehandler.cpp \ + $$PWD/qabstracturiresolver.cpp \ + $$PWD/qabstractxmlnodemodel.cpp \ + $$PWD/qabstractxmlpullprovider.cpp \ + $$PWD/qabstractxmlreceiver.cpp \ + $$PWD/qiodevicedelegate.cpp \ + $$PWD/qnetworkaccessdelegator.cpp \ + $$PWD/qpullbridge.cpp \ + $$PWD/qresourcedelegator.cpp \ + $$PWD/qsimplexmlnodemodel.cpp \ + $$PWD/qsourcelocation.cpp \ + $$PWD/quriloader.cpp \ + $$PWD/qxmlformatter.cpp \ + $$PWD/qxmlname.cpp \ + $$PWD/qxmlnamepool.cpp \ + $$PWD/qxmlquery.cpp \ + $$PWD/qxmlresultitems.cpp \ + $$PWD/qxmlschema.cpp \ + $$PWD/qxmlschema_p.cpp \ + $$PWD/qxmlschemavalidator.cpp \ + $$PWD/qxmlserializer.cpp \ + $$PWD/qcoloringmessagehandler.cpp \ + $$PWD/qcoloroutput.cpp diff --git a/src/xmlpatterns/api/qcoloringmessagehandler.cpp b/src/xmlpatterns/api/qcoloringmessagehandler.cpp new file mode 100644 index 0000000..7d3eb6f --- /dev/null +++ b/src/xmlpatterns/api/qcoloringmessagehandler.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QXmlStreamReader> + +#include "qcoloringmessagehandler_p.h" +#include "qxmlpatternistcli_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +ColoringMessageHandler::ColoringMessageHandler(QObject *parent) : QAbstractMessageHandler(parent) +{ + m_classToColor.insert(QLatin1String("XQuery-data"), Data); + m_classToColor.insert(QLatin1String("XQuery-expression"), Keyword); + m_classToColor.insert(QLatin1String("XQuery-function"), Keyword); + m_classToColor.insert(QLatin1String("XQuery-keyword"), Keyword); + m_classToColor.insert(QLatin1String("XQuery-type"), Keyword); + m_classToColor.insert(QLatin1String("XQuery-uri"), Data); + m_classToColor.insert(QLatin1String("XQuery-filepath"), Data); + + /* If you're tuning the colors, take it easy laddie. Take into account: + * + * - Get over your own taste, there's others too on this planet + * - Make sure it works well on black & white + * - Make sure it works well on white & black + */ + insertMapping(Location, CyanForeground); + insertMapping(ErrorCode, RedForeground); + insertMapping(Keyword, BlueForeground); + insertMapping(Data, BlueForeground); + insertMapping(RunningText, DefaultColor); +} + +void ColoringMessageHandler::handleMessage(QtMsgType type, + const QString &description, + const QUrl &identifier, + const QSourceLocation &sourceLocation) +{ + const bool hasLine = sourceLocation.line() != -1; + + switch(type) + { + case QtWarningMsg: + { + if(hasLine) + { + writeUncolored(QXmlPatternistCLI::tr("Warning in %1, at line %2, column %3: %4").arg(QString::fromLatin1(sourceLocation.uri().toEncoded()), + QString::number(sourceLocation.line()), + QString::number(sourceLocation.column()), + colorifyDescription(description))); + } + else + { + writeUncolored(QXmlPatternistCLI::tr("Warning in %1: %2").arg(QString::fromLatin1(sourceLocation.uri().toEncoded()), + colorifyDescription(description))); + } + + break; + } + case QtFatalMsg: + { + const QString errorCode(identifier.fragment()); + Q_ASSERT(!errorCode.isEmpty()); + QUrl uri(identifier); + uri.setFragment(QString()); + + QString location; + + if(sourceLocation.isNull()) + location = QXmlPatternistCLI::tr("Unknown location"); + else + location = QString::fromLatin1(sourceLocation.uri().toEncoded()); + + QString errorId; + /* If it's a standard error code, we don't want to output the + * whole URI. */ + if(uri.toString() == QLatin1String("http://www.w3.org/2005/xqt-errors")) + errorId = errorCode; + else + errorId = QString::fromLatin1(identifier.toEncoded()); + + if(hasLine) + { + writeUncolored(QXmlPatternistCLI::tr("Error %1 in %2, at line %3, column %4: %5").arg(colorify(errorId, ErrorCode), + colorify(location, Location), + colorify(QString::number(sourceLocation.line()), Location), + colorify(QString::number(sourceLocation.column()), Location), + colorifyDescription(description))); + } + else + { + writeUncolored(QXmlPatternistCLI::tr("Error %1 in %2: %3").arg(colorify(errorId, ErrorCode), + colorify(location, Location), + colorifyDescription(description))); + } + break; + } + case QtCriticalMsg: + /* Fallthrough. */ + case QtDebugMsg: + { + Q_ASSERT_X(false, Q_FUNC_INFO, + "message() is not supposed to receive QtCriticalMsg or QtDebugMsg."); + return; + } + } +} + +QString ColoringMessageHandler::colorifyDescription(const QString &in) const +{ + QXmlStreamReader reader(in); + QString result; + result.reserve(in.size()); + ColorType currentColor = RunningText; + + while(!reader.atEnd()) + { + reader.readNext(); + + switch(reader.tokenType()) + { + case QXmlStreamReader::StartElement: + { + if(reader.name() == QLatin1String("span")) + { + Q_ASSERT(m_classToColor.contains(reader.attributes().value(QLatin1String("class")).toString())); + currentColor = m_classToColor.value(reader.attributes().value(QLatin1String("class")).toString()); + } + + continue; + } + case QXmlStreamReader::Characters: + { + result.append(colorify(reader.text().toString(), currentColor)); + continue; + } + case QXmlStreamReader::EndElement: + { + currentColor = RunningText; + continue; + } + /* Fallthrough, */ + case QXmlStreamReader::StartDocument: + /* Fallthrough, */ + case QXmlStreamReader::EndDocument: + continue; + default: + Q_ASSERT_X(false, Q_FUNC_INFO, + "Unexpected node."); + } + } + + Q_ASSERT_X(!reader.hasError(), Q_FUNC_INFO, + "The output from Patternist must be well-formed."); + return result; +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qcoloringmessagehandler_p.h b/src/xmlpatterns/api/qcoloringmessagehandler_p.h new file mode 100644 index 0000000..3e8d18b --- /dev/null +++ b/src/xmlpatterns/api/qcoloringmessagehandler_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the XMLPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_ColoringMessageHandler_h +#define Patternist_ColoringMessageHandler_h + +#include <QHash> + +#include "qcoloroutput_p.h" +#include "qabstractmessagehandler.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + class ColoringMessageHandler : public QAbstractMessageHandler + , private ColorOutput + { + public: + ColoringMessageHandler(QObject *parent = 0); + + protected: + virtual void handleMessage(QtMsgType type, + const QString &description, + const QUrl &identifier, + const QSourceLocation &sourceLocation); + + private: + QString colorifyDescription(const QString &in) const; + + enum ColorType + { + RunningText, + Location, + ErrorCode, + Keyword, + Data + }; + + QHash<QString, ColorType> m_classToColor; + }; +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qcoloroutput.cpp b/src/xmlpatterns/api/qcoloroutput.cpp new file mode 100644 index 0000000..abfa656 --- /dev/null +++ b/src/xmlpatterns/api/qcoloroutput.cpp @@ -0,0 +1,377 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QFile> +#include <QHash> +#include <QTextCodec> + +#include "qcoloroutput_p.h" + +// TODO: rename insertMapping() to insertColorMapping() +// TODO: Use a smart pointer for managing ColorOutputPrivate *d; +// TODO: break out the C++ example into a snippet file + +/* This include must appear here, because if it appears at the beginning of the file for + * instance, it breaks build -- "qglobal.h:628: error: template with + * C linkage" -- on Mac OS X 10.4. */ +#ifndef Q_OS_WIN +#include <unistd.h> +#endif + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +namespace QPatternist +{ + class ColorOutputPrivate + { + public: + ColorOutputPrivate() : currentColorID(-1) + + { + /* - QIODevice::Unbuffered because we want it to appear when the user actually calls, performance + * is considered of lower priority. + */ + m_out.open(stderr, QIODevice::WriteOnly | QIODevice::Unbuffered); + + coloringEnabled = isColoringPossible(); + } + + ColorOutput::ColorMapping colorMapping; + int currentColorID; + bool coloringEnabled; + + static const char *const foregrounds[]; + static const char *const backgrounds[]; + + inline void write(const QString &msg) + { + m_out.write(msg.toLocal8Bit()); + } + + static QString escapeCode(const QString &in) + { + QString result; + result.append(QChar(0x1B)); + result.append(QLatin1Char('[')); + result.append(in); + result.append(QLatin1Char('m')); + return result; + } + + private: + QFile m_out; + + /*! + Returns true if it's suitable to send colored output to \c stderr. + */ + inline bool isColoringPossible() const + { +# if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) + /* Windows doesn't at all support ANSI escape codes, unless + * the user install a "device driver". See the Wikipedia links in the + * class documentation for details. */ + return false; +# else + /* We use QFile::handle() to get the file descriptor. It's a bit unsure + * whether it's 2 on all platforms and in all cases, so hopefully this layer + * of abstraction helps handle such cases. */ + return isatty(m_out.handle()); +# endif + } + }; +} + +const char *const ColorOutputPrivate::foregrounds[] = +{ + "0;30", + "0;34", + "0;32", + "0;36", + "0;31", + "0;35", + "0;33", + "0;37", + "1;30", + "1;34", + "1;32", + "1;36", + "1;31", + "1;35", + "1;33", + "1;37" +}; + +const char *const ColorOutputPrivate::backgrounds[] = +{ + "0;40", + "0;44", + "0;42", + "0;46", + "0;41", + "0;45", + "0;43" +}; + +/*! + \class ColorOutput + \since 4.4 + \nonreentrant + \brief Outputs colored messages to \c stderr. + \internal + + ColorOutput is a convenience class for outputting messages to \c + stderr using color escape codes, as mandated in ECMA-48. ColorOutput + will only color output when it is detected to be suitable. For + instance, if \c stderr is detected to be attached to a file instead + of a TTY, no coloring will be done. + + ColorOutput does its best attempt. but it is generally undefined + what coloring or effect the various coloring flags has. It depends + strongly on what terminal software that is being used. + + When using `echo -e 'my escape sequence'`, \c{\033} works as an + initiator but not when printing from a C++ program, despite having + escaped the backslash. That's why we below use characters with + value 0x1B. + + It can be convenient to subclass ColorOutput with a private scope, + such that the functions are directly available in the class using + it. + + \section1 Usage + + To output messages, call write() or writeUncolored(). write() takes + as second argument an integer, which ColorOutput uses as a lookup + key to find the color it should color the text in. The mapping from + keys to colors is done using insertMapping(). Typically this is used + by having enums for the various kinds of messages, which + subsequently are registered. + + \code + enum MyMessage + { + Error, + Important + }; + + ColorOutput output; + output.insertMapping(Error, ColorOutput::RedForeground); + output.insertMapping(Import, ColorOutput::BlueForeground); + + output.write("This is important", Important); + output.write("Jack, I'm only the selected official!", Error); + \endcode + + \sa {http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html} {Bash Prompt HOWTO, 6.1. Colours} + {http://linuxgazette.net/issue51/livingston-blade.html} {Linux Gazette, Tweaking Eterm, Edward Livingston-Blade} + {http://www.ecma-international.org/publications/standards/Ecma-048.htm} {Standard ECMA-48, Control Functions for Coded Character Sets, ECMA International}, + {http://en.wikipedia.org/wiki/ANSI_escape_code} {Wikipedia, ANSI escape code} + {http://linuxgazette.net/issue65/padala.html} {Linux Gazette, So You Like Color!, Pradeep Padala} + */ + +/*! + \enum ColorOutput::ColorCodeComponent + \value BlackForeground + \value BlueForeground + \value GreenForeground + \value CyanForeground + \value RedForeground + \value PurpleForeground + \value BrownForeground + \value LightGrayForeground + \value DarkGrayForeground + \value LightBlueForeground + \value LightGreenForeground + \value LightCyanForeground + \value LightRedForeground + \value LightPurpleForeground + \value YellowForeground + \value WhiteForeground + \value BlackBackground + \value BlueBackground + \value GreenBackground + \value CyanBackground + \value RedBackground + \value PurpleBackground + \value BrownBackground + + \value DefaultColor ColorOutput performs no coloring. This typically + means black on white or white on black, depending + on the settings of the user's terminal. + */ + +/*! + Sets the color mapping to be \a cMapping. + + Negative values are disallowed. + + \sa colorMapping(), insertMapping() + */ +void ColorOutput::setColorMapping(const ColorMapping &cMapping) +{ + d->colorMapping = cMapping; +} + +/*! + Returns the color mappings in use. + + \sa setColorMapping(), insertMapping() + */ +ColorOutput::ColorMapping ColorOutput::colorMapping() const +{ + return d->colorMapping; +} + +/*! + Constructs a ColorOutput instance, ready for use. + */ +ColorOutput::ColorOutput() : d(new ColorOutputPrivate()) +{ +} + +/*! + Destructs this ColorOutput instance. + */ +ColorOutput::~ColorOutput() +{ + delete d; +} + +/*! + Sends \a message to \c stderr, using the color looked up in colorMapping() using \a colorID. + + If \a color isn't available in colorMapping(), result and behavior is undefined. + + If \a colorID is 0, which is the default value, the previously used coloring is used. ColorOutput + is initialized to not color at all. + + If \a message is empty, effects are undefined. + + \a message will be printed as is. For instance, no line endings will be inserted. + */ +void ColorOutput::write(const QString &message, int colorID) +{ + d->write(colorify(message, colorID)); +} + +/*! + Writes \a message to \c stderr as if for instance + QTextStream would have been used, and adds a line ending at the end. + + This function can be practical to use such that one can use ColorOutput for all forms of writing. + */ +void ColorOutput::writeUncolored(const QString &message) +{ + d->write(message + QLatin1Char('\n')); +} + +/*! + Treats \a message and \a colorID identically to write(), but instead of writing + \a message to \c stderr, it is prepared for being written to \c stderr, but is then + returned. + + This is useful when the colored string is inserted into a translated string(dividing + the string into several small strings prevents proper translation). + */ +QString ColorOutput::colorify(const QString &message, int colorID) const +{ + Q_ASSERT_X(colorID == -1 || d->colorMapping.contains(colorID), Q_FUNC_INFO, + qPrintable(QString::fromLatin1("There is no color registered by id %1").arg(colorID))); + Q_ASSERT_X(!message.isEmpty(), Q_FUNC_INFO, "It makes no sense to attempt to print an empty string."); + + if(colorID != -1) + d->currentColorID = colorID; + + if(d->coloringEnabled && colorID != -1) + { + const int color(d->colorMapping.value(colorID)); + + /* If DefaultColor is set, we don't want to color it. */ + if(color & DefaultColor) + return message; + + const int foregroundCode = (int(color) & ForegroundMask) >> ForegroundShift; + const int backgroundCode = (int(color) & BackgroundMask) >> BackgroundShift; + QString finalMessage; + bool closureNeeded = false; + + if(foregroundCode) + { + finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::foregrounds[foregroundCode - 1]))); + closureNeeded = true; + } + + if(backgroundCode) + { + finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String(ColorOutputPrivate::backgrounds[backgroundCode - 1]))); + closureNeeded = true; + } + + finalMessage.append(message); + + if(closureNeeded) + { + finalMessage.append(QChar(0x1B)); + finalMessage.append(QLatin1String("[0m")); + } + + return finalMessage; + } + else + return message; +} + +/*! + Adds a color mapping from \a colorID to \a colorCode, for this ColorOutput instance. + + This is a convenience function for creating a ColorOutput::ColorMapping instance and + calling setColorMapping(). + + \sa colorMapping(), setColorMapping() + */ +void ColorOutput::insertMapping(int colorID, const ColorCode colorCode) +{ + d->colorMapping.insert(colorID, colorCode); +} + +QT_END_NAMESPACE diff --git a/src/xmlpatterns/api/qcoloroutput_p.h b/src/xmlpatterns/api/qcoloroutput_p.h new file mode 100644 index 0000000..1917ec7 --- /dev/null +++ b/src/xmlpatterns/api/qcoloroutput_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the XMLPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_ColorOutput_h +#define Patternist_ColorOutput_h + +#include <QtCore/QtGlobal> +#include <QtCore/QHash> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +namespace QPatternist +{ + class ColorOutputPrivate; + + class ColorOutput + { + enum + { + ForegroundShift = 10, + BackgroundShift = 20, + SpecialShift = 20, + ForegroundMask = ((1 << ForegroundShift) - 1) << ForegroundShift, + BackgroundMask = ((1 << BackgroundShift) - 1) << BackgroundShift + }; + + public: + enum ColorCodeComponent + { + BlackForeground = 1 << ForegroundShift, + BlueForeground = 2 << ForegroundShift, + GreenForeground = 3 << ForegroundShift, + CyanForeground = 4 << ForegroundShift, + RedForeground = 5 << ForegroundShift, + PurpleForeground = 6 << ForegroundShift, + BrownForeground = 7 << ForegroundShift, + LightGrayForeground = 8 << ForegroundShift, + DarkGrayForeground = 9 << ForegroundShift, + LightBlueForeground = 10 << ForegroundShift, + LightGreenForeground = 11 << ForegroundShift, + LightCyanForeground = 12 << ForegroundShift, + LightRedForeground = 13 << ForegroundShift, + LightPurpleForeground = 14 << ForegroundShift, + YellowForeground = 15 << ForegroundShift, + WhiteForeground = 16 << ForegroundShift, + + BlackBackground = 1 << BackgroundShift, + BlueBackground = 2 << BackgroundShift, + GreenBackground = 3 << BackgroundShift, + CyanBackground = 4 << BackgroundShift, + RedBackground = 5 << BackgroundShift, + PurpleBackground = 6 << BackgroundShift, + BrownBackground = 7 << BackgroundShift, + DefaultColor = 1 << SpecialShift + }; + + typedef QFlags<ColorCodeComponent> ColorCode; + typedef QHash<int, ColorCode> ColorMapping; + + ColorOutput(); + ~ColorOutput(); + + void setColorMapping(const ColorMapping &cMapping); + ColorMapping colorMapping() const; + void insertMapping(int colorID, const ColorCode colorCode); + + void writeUncolored(const QString &message); + void write(const QString &message, int color = -1); + QString colorify(const QString &message, int color = -1) const; + + private: + ColorOutputPrivate *d; + Q_DISABLE_COPY(ColorOutput) + }; +} + +Q_DECLARE_OPERATORS_FOR_FLAGS(QPatternist::ColorOutput::ColorCode) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/api/qxmlpatternistcli_p.h b/src/xmlpatterns/api/qxmlpatternistcli_p.h new file mode 100644 index 0000000..072e4aa --- /dev/null +++ b/src/xmlpatterns/api/qxmlpatternistcli_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the XMLPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#ifndef Patternist_Cli_h +#define Patternist_Cli_h + +#include <QCoreApplication> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QXmlPatternistCLI +{ +public: + Q_DECLARE_TR_FUNCTIONS(QXmlPatternistCLI) +private: + inline QXmlPatternistCLI(); + Q_DISABLE_COPY(QXmlPatternistCLI) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/xmlpatterns/xmlpatterns.pro b/src/xmlpatterns/xmlpatterns.pro index 1df497d..a224762 100644 --- a/src/xmlpatterns/xmlpatterns.pro +++ b/src/xmlpatterns/xmlpatterns.pro @@ -1,15 +1,14 @@ -TARGET = QtXmlPatterns -QPRO_PWD = $$PWD -QT = core network -DEFINES += QT_BUILD_XMLPATTERNS_LIB QT_NO_USING_NAMESPACE +TARGET = QtXmlPatterns +QPRO_PWD = $$PWD +QT = core \ + network +DEFINES += QT_BUILD_XMLPATTERNS_LIB \ + QT_NO_USING_NAMESPACE win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x61000000 - -unix:QMAKE_PKGCONFIG_REQUIRES = QtCore QtNetwork - +unix:QMAKE_PKGCONFIG_REQUIRES = QtCore \ + QtNetwork include(../qbase.pri) - PRECOMPILED_HEADER = ../corelib/global/qt_pch.h - include($$PWD/common.pri) include($$PWD/acceltree/acceltree.pri) include($$PWD/api/api.pri) @@ -25,14 +24,13 @@ include($$PWD/schema/schema.pri) include($$PWD/type/type.pri) include($$PWD/utils/utils.pri) include($$PWD/qobjectmodel/qobjectmodel.pri, "", true) +wince*:# The Microsoft MIPS compiler crashes if /Og is specified +: -wince*: { - # The Microsoft MIPS compiler crashes if /Og is specified - # -O2/1 expands to /Og plus additional arguments. - contains(DEFINES, MIPS): { - QMAKE_CXXFLAGS_RELEASE ~= s/-O2/-Oi -Ot -Oy -Ob2/ - QMAKE_CXXFLAGS_RELEASE ~= s/-O1/-Os -Oy -Ob2/ - } +# -O2/1 expands to /Og plus additional arguments. +contains(DEFINES, MIPS): { + QMAKE_CXXFLAGS_RELEASE ~= s/-O2/-Oi -Ot -Oy -Ob2/ + QMAKE_CXXFLAGS_RELEASE ~= s/-O1/-Os -Oy -Ob2/ } - -symbian:TARGET.UID3=0x2001E62B +symbian:TARGET.UID3 = 0x2001E62B +HEADERS += |