diff options
Diffstat (limited to 'src')
134 files changed, 3312 insertions, 1763 deletions
diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-arabic.c b/src/3rdparty/harfbuzz/src/harfbuzz-arabic.c index 4d85c19..3837087 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-arabic.c +++ b/src/3rdparty/harfbuzz/src/harfbuzz-arabic.c @@ -489,6 +489,56 @@ static void getArabicProperties(const unsigned short *chars, int len, HB_ArabicP */ } +static Joining getNkoJoining(unsigned short uc) +{ + if (uc < 0x7ca) + return JNone; + if (uc <= 0x7ea) + return JDual; + if (uc <= 0x7f3) + return JTransparent; + if (uc <= 0x7f9) + return JNone; + if (uc == 0x7fa) + return JCausing; + return JNone; +} + +static void getNkoProperties(const unsigned short *chars, int len, HB_ArabicProperties *properties) +{ + int lastPos = 0; + int i = 0; + + Joining j = getNkoJoining(chars[0]); + ArabicShape shape = joining_table[XIsolated][j].form2; + properties[0].justification = HB_NoJustification; + + for (i = 1; i < len; ++i) { + properties[i].justification = (HB_GetUnicodeCharCategory(chars[i]) == HB_Separator_Space) ? + ArabicSpace : ArabicNone; + + j = getNkoJoining(chars[i]); + + if (j == JTransparent) { + properties[i].shape = XIsolated; + continue; + } + + properties[lastPos].shape = joining_table[shape][j].form1; + shape = joining_table[shape][j].form2; + + + lastPos = i; + } + properties[lastPos].shape = joining_table[shape][JNone].form1; + + + /* + for (int i = 0; i < len; ++i) + qDebug("nko properties(%d): uc=%x shape=%d, justification=%d", i, chars[i], properties[i].shape, properties[i].justification); + */ +} + /* // The unicode to unicode shaping codec. // does only presentation forms B at the moment, but that should be enough for @@ -1012,7 +1062,10 @@ static HB_Bool arabicSyriacOpenTypeShape(HB_ShaperItem *item, HB_Bool *ot_ok) if (f + l + item->item.pos < item->stringLength) { ++l; } - getArabicProperties(uc+f, l, props); + if (item->item.script == HB_Script_Nko) + getNkoProperties(uc+f, l, props); + else + getArabicProperties(uc+f, l, props); for (i = 0; i < (int)item->num_glyphs; i++) { apply[i] = 0; @@ -1051,7 +1104,8 @@ HB_Bool HB_ArabicShape(HB_ShaperItem *item) HB_Bool haveGlyphs; HB_STACKARRAY(HB_UChar16, shapedChars, item->item.length); - assert(item->item.script == HB_Script_Arabic || item->item.script == HB_Script_Syriac); + assert(item->item.script == HB_Script_Arabic || item->item.script == HB_Script_Syriac + || item->item.script == HB_Script_Nko); #ifndef NO_OPENTYPE @@ -1065,7 +1119,7 @@ HB_Bool HB_ArabicShape(HB_ShaperItem *item) } #endif - if (item->item.script == HB_Script_Syriac) + if (item->item.script != HB_Script_Arabic) return HB_BasicShape(item); shapedString(item->string, item->stringLength, item->item.pos, item->item.length, shapedChars, &slen, diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp b/src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp index 48f4f90..3008fca 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp +++ b/src/3rdparty/harfbuzz/src/harfbuzz-indic.cpp @@ -566,7 +566,7 @@ static const unsigned char indicPosition[0xe00-0x900] = { None, None, None, None, None, None, None, None, - None, None, None, None, + Below, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, @@ -1252,7 +1252,9 @@ static bool indic_shape_syllable(HB_Bool openType, HB_ShaperItem *item, bool inv // farther than 3 consonants from the end of the syllable. // #### replace the HasReph property by testing if the feature exists in the font! if (form(*uc) == Consonant || (script == HB_Script_Bengali && form(*uc) == IndependentVowel)) { - beginsWithRa = (properties & HasReph) && ((len > 2) && *uc == ra && *(uc+1) == halant); + if ((properties & HasReph) && (len > 2) && + (*uc == ra || *uc == 0x9f0) && *(uc+1) == halant) + beginsWithRa = true; if (beginsWithRa && form(*(uc+2)) == Control) beginsWithRa = false; @@ -1744,6 +1746,10 @@ static int indic_nextSyllableBoundary(HB_Script script, const HB_UChar16 *s, int ++pos; continue; } + if (script == HB_Script_Malayalam && state == Matra && uc[pos-1] == 0x0d41) { + ++pos; + continue; + } goto finish; case Nukta: if (state == Consonant) diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp b/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp index f92bb55..f3ec8e1 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp +++ b/src/3rdparty/harfbuzz/src/harfbuzz-shaper.cpp @@ -637,7 +637,9 @@ const HB_ScriptEngine HB_ScriptEngines[] = { // Runic { HB_BasicShape, 0 }, // Khmer - { HB_KhmerShape, HB_KhmerAttributes } + { HB_KhmerShape, HB_KhmerAttributes }, + // N'Ko + { HB_ArabicShape, 0} }; void HB_GetCharAttributes(const HB_UChar16 *string, hb_uint32 stringLength, @@ -877,7 +879,9 @@ static const OTScripts ot_scripts [] = { // Runic { HB_MAKE_TAG('r', 'u', 'n', 'r'), 0 }, // Khmer - { HB_MAKE_TAG('k', 'h', 'm', 'r'), 1 } + { HB_MAKE_TAG('k', 'h', 'm', 'r'), 1 }, + // N'Ko + { HB_MAKE_TAG('n', 'k', 'o', ' '), 1 } }; enum { NumOTScripts = sizeof(ot_scripts)/sizeof(OTScripts) }; diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-shaper.h b/src/3rdparty/harfbuzz/src/harfbuzz-shaper.h index d2357f43..f7c7714 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-shaper.h +++ b/src/3rdparty/harfbuzz/src/harfbuzz-shaper.h @@ -62,6 +62,7 @@ typedef enum { HB_Script_Ogham, HB_Script_Runic, HB_Script_Khmer, + HB_Script_Nko, HB_Script_Inherited, HB_ScriptCount = HB_Script_Inherited /* @@ -102,7 +103,6 @@ typedef enum { HB_Script_Cuneiform = Common, HB_Script_Phoenician = Common, HB_Script_PhagsPa = Common, - HB_Script_Nko = Common */ } HB_Script; diff --git a/src/3rdparty/harfbuzz/tests/shaping/main.cpp b/src/3rdparty/harfbuzz/tests/shaping/main.cpp index a7ea417..12fa7c4 100644 --- a/src/3rdparty/harfbuzz/tests/shaping/main.cpp +++ b/src/3rdparty/harfbuzz/tests/shaping/main.cpp @@ -181,6 +181,7 @@ private slots: void sinhala(); void khmer(); + void nko(); void linearB(); }; @@ -515,6 +516,12 @@ void tst_QScriptEngine::bengali() { 0x179, 0x151, 0x172, 0x0 } }, { { 0x995, 0x9c7, 0x9d7, 0x0 }, { 0x179, 0x151, 0x17e, 0x0 } }, + { { 0x9b0, 0x9cd, 0x9ad, 0x0 }, + { 0x168, 0x276, 0x0 } }, + { { 0x9f0, 0x9cd, 0x9ad, 0x0 }, + { 0x168, 0x276, 0x0 } }, + { { 0x9f1, 0x9cd, 0x9ad, 0x0 }, + { 0x191, 0x17d, 0x168, 0x0 } }, { {0}, {0} } }; @@ -652,6 +659,12 @@ void tst_QScriptEngine::bengali() { 0x01fe, 0x0 } }, { { 0x09b0, 0x09cd, 0x09a8, 0x09cd, 0x200d, 0x0 }, { 0x10b, 0x167, 0x0 } }, + { { 0x9b0, 0x9cd, 0x9ad, 0x0 }, + { 0xa1, 0x167, 0x0 } }, + { { 0x9f0, 0x9cd, 0x9ad, 0x0 }, + { 0xa1, 0x167, 0x0 } }, + { { 0x9f1, 0x9cd, 0x9ad, 0x0 }, + { 0x11c, 0xa1, 0x0 } }, { {0}, {0} } }; @@ -967,6 +980,8 @@ void tst_QScriptEngine::malayalam() { 0x5e, 0x34, 0x65, 0x0 } }, { { 0xd15, 0xd57, 0x0 }, { 0x34, 0x65, 0x0 } }, + { { 0xd1f, 0xd4d, 0xd1f, 0xd41, 0xd4d, 0x0 }, + { 0x69, 0x5b, 0x64, 0x0 } }, { {0}, {0} } }; @@ -1061,6 +1076,40 @@ void tst_QScriptEngine::khmer() } } +void tst_QScriptEngine::nko() +{ + { + FT_Face face = loadFace("DejaVuSans.ttf"); + if (face) { + const ShapeTable shape_table [] = { + { { 0x7ca, 0x0 }, + { 0x5c1, 0x0 } }, + { { 0x7ca, 0x7ca, 0x0 }, + { 0x14db, 0x14d9, 0x0 } }, + { { 0x7ca, 0x7fa, 0x7ca, 0x0 }, + { 0x14db, 0x5ec, 0x14d9, 0x0 } }, + { { 0x7ca, 0x7f3, 0x7ca, 0x0 }, + { 0x14db, 0x5e7, 0x14d9, 0x0 } }, + { { 0x7ca, 0x7f3, 0x7fa, 0x7ca, 0x0 }, + { 0x14db, 0x5e7, 0x5ec, 0x14d9, 0x0 } }, + { {0}, {0} } + }; + + + const ShapeTable *s = shape_table; + while (s->unicode[0]) { + QVERIFY( shaping(face, s, HB_Script_Nko) ); + ++s; + } + + FT_Done_Face(face); + } else { + QSKIP("couln't find DejaVuSans.ttf", SkipAll); + } + } +} + + void tst_QScriptEngine::linearB() { { diff --git a/src/3rdparty/phonon/ds9/videorenderer_soft.cpp b/src/3rdparty/phonon/ds9/videorenderer_soft.cpp index 82d6235..f7d42cf 100644 --- a/src/3rdparty/phonon/ds9/videorenderer_soft.cpp +++ b/src/3rdparty/phonon/ds9/videorenderer_soft.cpp @@ -661,7 +661,10 @@ namespace Phonon #ifndef QT_NO_OPENGL - if (painter.paintEngine() && painter.paintEngine()->type() == QPaintEngine::OpenGL && checkGLPrograms()) { + if (painter.paintEngine() && + (painter.paintEngine()->type() == QPaintEngine::OpenGL || painter.paintEngine()->type() == QPaintEngine::OpenGL2) + && checkGLPrograms()) { + //for now we only support YUV (both YV12 and YUY2) updateTexture(); @@ -673,6 +676,7 @@ namespace Phonon } //let's draw the texture + painter.beginNativePainting(); //Let's pass the other arguments const Program prog = (m_inputPin->connectedType().subtype == MEDIASUBTYPE_YV12) ? YV12toRGB : YUY2toRGB; @@ -722,6 +726,7 @@ namespace Phonon glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_FRAGMENT_PROGRAM_ARB); + painter.endNativePainting(); return; } else #endif diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index a4c7e29..be99b3b 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -50,7 +50,7 @@ animations that plug into the rest of the animation framework. The progress of an animation is given by its current time - (currentTime()), which is measured in milliseconds from the start + (currentLoopTime()), which is measured in milliseconds from the start of the animation (0) to its end (duration()). The value is updated automatically while the animation is running. It can also be set directly with setCurrentTime(). @@ -115,7 +115,7 @@ */ /*! - \fn QAbstractAnimation::stateChanged(QAbstractAnimation::State oldState, QAbstractAnimation::State newState) + \fn QAbstractAnimation::stateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State oldState) QAbstractAnimation emits this signal whenever the state of the animation has changed from \a oldState to \a newState. This signal is emitted after the virtual @@ -165,8 +165,8 @@ Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer) QUnifiedTimer::QUnifiedTimer() : QObject(), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL), - currentAnimationIdx(0), consistentTiming(false), isPauseTimerActive(false), - runningLeafAnimations(0) + currentAnimationIdx(0), consistentTiming(false), slowMode(false), + isPauseTimerActive(false), runningLeafAnimations(0) { } @@ -191,8 +191,10 @@ void QUnifiedTimer::ensureTimerUpdate() void QUnifiedTimer::updateAnimationsTime() { // ignore consistentTiming in case the pause timer is active - const int delta = (consistentTiming && !isPauseTimerActive) ? + int delta = (consistentTiming && !isPauseTimerActive) ? timingInterval : time.elapsed() - lastTick; + if (slowMode) + delta /= 5; lastTick = time.elapsed(); //we make sure we only call update time if the time has actually changed @@ -213,6 +215,10 @@ void QUnifiedTimer::restartAnimationTimer() { if (runningLeafAnimations == 0 && !runningPauseAnimations.isEmpty()) { int closestTimeToFinish = closestPauseAnimationTimeToFinish(); + if (closestTimeToFinish < 0) { + qDebug() << runningPauseAnimations; + qDebug() << closestPauseAnimationTimeToFinish(); + } animationTimer.start(closestTimeToFinish, this); isPauseTimerActive = true; } else if (!animationTimer.isActive() || isPauseTimerActive) { @@ -287,9 +293,11 @@ void QUnifiedTimer::registerRunningAnimation(QAbstractAnimation *animation) if (QAbstractAnimationPrivate::get(animation)->isGroup) return; - if (QAbstractAnimationPrivate::get(animation)->isPause) + if (QAbstractAnimationPrivate::get(animation)->isPause) { + if (animation->duration() == -1) + qDebug() << "toto"; runningPauseAnimations << animation; - else + } else runningLeafAnimations++; } @@ -313,9 +321,9 @@ int QUnifiedTimer::closestPauseAnimationTimeToFinish() int timeToFinish; if (animation->direction() == QAbstractAnimation::Forward) - timeToFinish = animation->duration() - animation->currentTime(); + timeToFinish = animation->duration() - animation->currentLoopTime(); else - timeToFinish = animation->currentTime(); + timeToFinish = animation->currentLoopTime(); if (timeToFinish < closestTimeToFinish) closestTimeToFinish = timeToFinish; @@ -347,34 +355,32 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) state = newState; QWeakPointer<QAbstractAnimation> guard(q); - q->updateState(oldState, newState); - if (!guard) - return; + //(un)registration of the animation must always happen before calls to + //virtual function (updateState) to ensure a correct state of the timer + bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped; + if (oldState == QAbstractAnimation::Running) { + if (newState == QAbstractAnimation::Paused && hasRegisteredTimer) + QUnifiedTimer::instance()->ensureTimerUpdate(); + //the animation, is not running any more + QUnifiedTimer::instance()->unregisterAnimation(q); + } else if (newState == QAbstractAnimation::Running) { + QUnifiedTimer::instance()->registerAnimation(q, isTopLevel); + } - //this is to be safe if updateState changes the state - if (state == oldState) + q->updateState(newState, oldState); + if (!guard || newState != state) //this is to be safe if updateState changes the state return; // Notify state change - emit q->stateChanged(oldState, newState); - if (!guard) + emit q->stateChanged(newState, oldState); + if (!guard || newState != state) //this is to be safe if updateState changes the state return; switch (state) { case QAbstractAnimation::Paused: - if (hasRegisteredTimer) - // currentTime needs to be updated if pauseTimer is active - QUnifiedTimer::instance()->ensureTimerUpdate(); - if (!guard) - return; - //here we're sure that we were in running state before and that the - //animation is currently registered - QUnifiedTimer::instance()->unregisterAnimation(q); break; case QAbstractAnimation::Running: { - bool isTopLevel = !group || group->state() == QAbstractAnimation::Stopped; - QUnifiedTimer::instance()->registerAnimation(q, isTopLevel); // this ensures that the value is updated now that the animation is running if (oldState == QAbstractAnimation::Stopped) { @@ -389,15 +395,10 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) case QAbstractAnimation::Stopped: // Leave running state. int dura = q->duration(); - if (!guard) - return; if (deleteWhenStopped) q->deleteLater(); - if (oldState == QAbstractAnimation::Running) - QUnifiedTimer::instance()->unregisterAnimation(q); - if (dura == -1 || loopCount < 0 || (oldDirection == QAbstractAnimation::Forward && (oldCurrentTime * (oldCurrentLoop + 1)) == (dura * loopCount)) || (oldDirection == QAbstractAnimation::Backward && oldCurrentTime == 0)) { @@ -642,6 +643,18 @@ int QAbstractAnimation::totalDuration() const } /*! + Returns the current time inside the current loop. It can go from 0 to duration(). + + \sa duration(), currentTime +*/ + +int QAbstractAnimation::currentLoopTime() const +{ + Q_D(const QAbstractAnimation); + return d->currentTime; +} + +/*! \property QAbstractAnimation::currentTime \brief the current time and progress of the animation @@ -650,17 +663,14 @@ int QAbstractAnimation::totalDuration() const the animation run, setting the current time automatically as the animation progresses. - The animation's current time starts at 0, and ends at duration(). If the - animation's loopCount is larger than 1, the current time will rewind and - start at 0 again for the consecutive loops. If the animation has a pause. - currentTime will also include the duration of the pause. + The animation's current time starts at 0, and ends at totalDuration(). - \sa loopCount + \sa loopCount, currentLoopTime */ int QAbstractAnimation::currentTime() const { Q_D(const QAbstractAnimation); - return d->currentTime; + return d->totalCurrentTime; } void QAbstractAnimation::setCurrentTime(int msecs) { @@ -734,7 +744,7 @@ void QAbstractAnimation::start(DeletionPolicy policy) signal, and state() returns Stopped. The current time is not changed. If the animation stops by itself after reaching the end (i.e., - currentTime() == duration() and currentLoop() > loopCount() - 1), the + currentLoopTime() == duration() and currentLoop() > loopCount() - 1), the finished() signal is emitted. \sa start(), state() @@ -784,6 +794,21 @@ void QAbstractAnimation::resume() } /*! + If \a paused is true, the animation is paused. + If \a paused is false, the animation is resumed. + + \sa state(), pause(), resume() +*/ +void QAbstractAnimation::setPaused(bool paused) +{ + if (paused) + pause(); + else + resume(); +} + + +/*! \reimp */ bool QAbstractAnimation::event(QEvent *event) @@ -806,8 +831,8 @@ bool QAbstractAnimation::event(QEvent *event) \sa start(), stop(), pause(), resume() */ -void QAbstractAnimation::updateState(QAbstractAnimation::State oldState, - QAbstractAnimation::State newState) +void QAbstractAnimation::updateState(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState) { Q_UNUSED(oldState); Q_UNUSED(newState); diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h index 3d608b6..3c6e12f 100644 --- a/src/corelib/animation/qabstractanimation.h +++ b/src/corelib/animation/qabstractanimation.h @@ -95,6 +95,9 @@ public: Direction direction() const; void setDirection(Direction direction); + int currentTime() const; + int currentLoopTime() const; + int loopCount() const; void setLoopCount(int loopCount); int currentLoop() const; @@ -102,11 +105,9 @@ public: virtual int duration() const = 0; int totalDuration() const; - int currentTime() const; - Q_SIGNALS: void finished(); - void stateChanged(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + void stateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); void currentLoopChanged(int currentLoop); void directionChanged(QAbstractAnimation::Direction); @@ -114,6 +115,7 @@ public Q_SLOTS: void start(QAbstractAnimation::DeletionPolicy policy = KeepWhenStopped); void pause(); void resume(); + void setPaused(bool); void stop(); void setCurrentTime(int msecs); @@ -122,7 +124,7 @@ protected: bool event(QEvent *event); virtual void updateCurrentTime(int currentTime) = 0; - virtual void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); virtual void updateDirection(QAbstractAnimation::Direction direction); private: diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h index f989bce..720e68d 100644 --- a/src/corelib/animation/qabstractanimation_p.h +++ b/src/corelib/animation/qabstractanimation_p.h @@ -138,6 +138,9 @@ public: */ void setConsistentTiming(bool consistent) { consistentTiming = consistent; } + //this facilitates fine-tuning of complex animations + void setSlowModeEnabled(bool enabled) { slowMode = enabled; } + /* this is used for updating the currentTime of all animations in case the pause timer is active or, otherwise, only of the animation passed as parameter. @@ -164,6 +167,7 @@ private: int timingInterval; int currentAnimationIdx; bool consistentTiming; + bool slowMode; // bool to indicate that only pause animations are active bool isPauseTimerActive; diff --git a/src/corelib/animation/qanimationgroup.cpp b/src/corelib/animation/qanimationgroup.cpp index 40f5936..64282ea 100644 --- a/src/corelib/animation/qanimationgroup.cpp +++ b/src/corelib/animation/qanimationgroup.cpp @@ -70,7 +70,7 @@ QAnimationGroup provides methods for adding and retrieving animations. Besides that, you can remove animations by calling remove(), and clear the animation group by calling - clearAnimations(). You may keep track of changes in the group's + clear(). You may keep track of changes in the group's animations by listening to QEvent::ChildAdded and QEvent::ChildRemoved events. @@ -151,7 +151,7 @@ int QAnimationGroup::animationCount() const Returns the index of \a animation. The returned index can be passed to the other functions that take an index as an argument. - \sa insertAnimationAt(), animationAt(), takeAnimationAt() + \sa insertAnimation(), animationAt(), takeAnimation() */ int QAnimationGroup::indexOfAnimation(QAbstractAnimation *animation) const { @@ -160,7 +160,7 @@ int QAnimationGroup::indexOfAnimation(QAbstractAnimation *animation) const } /*! - Adds \a animation to this group. This will call insertAnimationAt with + Adds \a animation to this group. This will call insertAnimation with index equals to animationCount(). \note The group takes ownership of the animation. @@ -170,7 +170,7 @@ int QAnimationGroup::indexOfAnimation(QAbstractAnimation *animation) const void QAnimationGroup::addAnimation(QAbstractAnimation *animation) { Q_D(QAnimationGroup); - insertAnimationAt(d->animations.count(), animation); + insertAnimation(d->animations.count(), animation); } /*! @@ -180,14 +180,14 @@ void QAnimationGroup::addAnimation(QAbstractAnimation *animation) \note The group takes ownership of the animation. - \sa takeAnimationAt(), addAnimation(), indexOfAnimation(), removeAnimation() + \sa takeAnimation(), addAnimation(), indexOfAnimation(), removeAnimation() */ -void QAnimationGroup::insertAnimationAt(int index, QAbstractAnimation *animation) +void QAnimationGroup::insertAnimation(int index, QAbstractAnimation *animation) { Q_D(QAnimationGroup); if (index < 0 || index > d->animations.size()) { - qWarning("QAnimationGroup::insertAnimationAt: index is out of bounds"); + qWarning("QAnimationGroup::insertAnimation: index is out of bounds"); return; } @@ -205,7 +205,7 @@ void QAnimationGroup::insertAnimationAt(int index, QAbstractAnimation *animation Removes \a animation from this group. The ownership of \a animation is transferred to the caller. - \sa takeAnimationAt(), insertAnimationAt(), addAnimation() + \sa takeAnimation(), insertAnimation(), addAnimation() */ void QAnimationGroup::removeAnimation(QAbstractAnimation *animation) { @@ -221,7 +221,7 @@ void QAnimationGroup::removeAnimation(QAbstractAnimation *animation) return; } - takeAnimationAt(index); + takeAnimation(index); } /*! @@ -229,13 +229,13 @@ void QAnimationGroup::removeAnimation(QAbstractAnimation *animation) \note The ownership of the animation is transferred to the caller. - \sa removeAnimation(), addAnimation(), insertAnimationAt(), indexOfAnimation() + \sa removeAnimation(), addAnimation(), insertAnimation(), indexOfAnimation() */ -QAbstractAnimation *QAnimationGroup::takeAnimationAt(int index) +QAbstractAnimation *QAnimationGroup::takeAnimation(int index) { Q_D(QAnimationGroup); if (index < 0 || index >= d->animations.size()) { - qWarning("QAnimationGroup::takeAnimationAt: no animation at index %d", index); + qWarning("QAnimationGroup::takeAnimation: no animation at index %d", index); return 0; } QAbstractAnimation *animation = d->animations.at(index); @@ -254,7 +254,7 @@ QAbstractAnimation *QAnimationGroup::takeAnimationAt(int index) \sa addAnimation(), removeAnimation() */ -void QAnimationGroup::clearAnimations() +void QAnimationGroup::clear() { Q_D(QAnimationGroup); qDeleteAll(d->animations); @@ -279,7 +279,7 @@ bool QAnimationGroup::event(QEvent *event) // case it might be called from the destructor. int index = d->animations.indexOf(a); if (index != -1) - takeAnimationAt(index); + takeAnimation(index); } return QAbstractAnimation::event(event); } diff --git a/src/corelib/animation/qanimationgroup.h b/src/corelib/animation/qanimationgroup.h index 86368a3..416ce3f 100644 --- a/src/corelib/animation/qanimationgroup.h +++ b/src/corelib/animation/qanimationgroup.h @@ -65,10 +65,10 @@ public: int animationCount() const; int indexOfAnimation(QAbstractAnimation *animation) const; void addAnimation(QAbstractAnimation *animation); - void insertAnimationAt(int index, QAbstractAnimation *animation); + void insertAnimation(int index, QAbstractAnimation *animation); void removeAnimation(QAbstractAnimation *animation); - QAbstractAnimation *takeAnimationAt(int index); - void clearAnimations(); + QAbstractAnimation *takeAnimation(int index); + void clear(); protected: QAnimationGroup(QAnimationGroupPrivate &dd, QObject *parent); diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp index 0a04c14..2d37d10 100644 --- a/src/corelib/animation/qparallelanimationgroup.cpp +++ b/src/corelib/animation/qparallelanimationgroup.cpp @@ -182,11 +182,11 @@ void QParallelAnimationGroup::updateCurrentTime(int currentTime) /*! \reimp */ -void QParallelAnimationGroup::updateState(QAbstractAnimation::State oldState, - QAbstractAnimation::State newState) +void QParallelAnimationGroup::updateState(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState) { Q_D(QParallelAnimationGroup); - QAnimationGroup::updateState(oldState, newState); + QAnimationGroup::updateState(newState, oldState); switch (newState) { case Stopped: diff --git a/src/corelib/animation/qparallelanimationgroup.h b/src/corelib/animation/qparallelanimationgroup.h index 1cab91e..18ec885 100644 --- a/src/corelib/animation/qparallelanimationgroup.h +++ b/src/corelib/animation/qparallelanimationgroup.h @@ -68,7 +68,7 @@ protected: bool event(QEvent *event); void updateCurrentTime(int currentTime); - void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); void updateDirection(QAbstractAnimation::Direction direction); private: diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp index 21e5b08..1b3b654 100644 --- a/src/corelib/animation/qpauseanimation.cpp +++ b/src/corelib/animation/qpauseanimation.cpp @@ -56,7 +56,7 @@ It is not necessary to construct a QPauseAnimation yourself. QSequentialAnimationGroup provides the convenience functions \l{QSequentialAnimationGroup::}{addPause()} and - \l{QSequentialAnimationGroup::}{insertPauseAt()}. These functions + \l{QSequentialAnimationGroup::}{insertPause()}. These functions simply take the number of milliseconds the pause should last. \sa QSequentialAnimationGroup diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp index 4742e54..3065083 100644 --- a/src/corelib/animation/qpropertyanimation.cpp +++ b/src/corelib/animation/qpropertyanimation.cpp @@ -250,8 +250,8 @@ void QPropertyAnimation::updateCurrentValue(const QVariant &value) If the startValue is not defined when the state of the animation changes from Stopped to Running, the current property value is used as the initial value for the animation. */ -void QPropertyAnimation::updateState(QAbstractAnimation::State oldState, - QAbstractAnimation::State newState) +void QPropertyAnimation::updateState(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState) { Q_D(QPropertyAnimation); @@ -260,7 +260,7 @@ void QPropertyAnimation::updateState(QAbstractAnimation::State oldState, return; } - QVariantAnimation::updateState(oldState, newState); + QVariantAnimation::updateState(newState, oldState); QPropertyAnimation *animToStop = 0; { diff --git a/src/corelib/animation/qpropertyanimation.h b/src/corelib/animation/qpropertyanimation.h index 2e2ca3a..61efed9 100644 --- a/src/corelib/animation/qpropertyanimation.h +++ b/src/corelib/animation/qpropertyanimation.h @@ -73,7 +73,7 @@ public: protected: bool event(QEvent *event); void updateCurrentValue(const QVariant &value); - void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); private: Q_DISABLE_COPY(QPropertyAnimation) diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp index 5ca560a..861e26e 100644 --- a/src/corelib/animation/qsequentialanimationgroup.cpp +++ b/src/corelib/animation/qsequentialanimationgroup.cpp @@ -50,7 +50,7 @@ another has finished playing. The animations are played in the order they are added to the group (using \l{QAnimationGroup::}{addAnimation()} or - \l{QAnimationGroup::}{insertAnimationAt()}). The animation group + \l{QAnimationGroup::}{insertAnimation()}). The animation group finishes when its last animation has finished. At each moment there is at most one animation that is active in @@ -59,7 +59,7 @@ A sequential animation group can be treated as any other animation, i.e., it can be started, stopped, and added to other - groups. You can also call addPause() or insertPauseAt() to add a + groups. You can also call addPause() or insertPause() to add a pause to a sequential animation group. \code @@ -269,7 +269,7 @@ QSequentialAnimationGroup::~QSequentialAnimationGroup() \l{QAnimationGroup::animationCount()}{animationCount} will be increased by one. - \sa insertPauseAt(), QAnimationGroup::addAnimation() + \sa insertPause(), QAnimationGroup::addAnimation() */ QPauseAnimation *QSequentialAnimationGroup::addPause(int msecs) { @@ -282,19 +282,19 @@ QPauseAnimation *QSequentialAnimationGroup::addPause(int msecs) Inserts a pause of \a msecs milliseconds at \a index in this animation group. - \sa addPause(), QAnimationGroup::insertAnimationAt() + \sa addPause(), QAnimationGroup::insertAnimation() */ -QPauseAnimation *QSequentialAnimationGroup::insertPauseAt(int index, int msecs) +QPauseAnimation *QSequentialAnimationGroup::insertPause(int index, int msecs) { Q_D(const QSequentialAnimationGroup); if (index < 0 || index > d->animations.size()) { - qWarning("QSequentialAnimationGroup::insertPauseAt: index is out of bounds"); + qWarning("QSequentialAnimationGroup::insertPause: index is out of bounds"); return 0; } QPauseAnimation *pause = new QPauseAnimation(msecs); - insertAnimationAt(index, pause); + insertAnimation(index, pause); return pause; } @@ -382,11 +382,11 @@ void QSequentialAnimationGroup::updateCurrentTime(int currentTime) /*! \reimp */ -void QSequentialAnimationGroup::updateState(QAbstractAnimation::State oldState, - QAbstractAnimation::State newState) +void QSequentialAnimationGroup::updateState(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState) { Q_D(QSequentialAnimationGroup); - QAnimationGroup::updateState(oldState, newState); + QAnimationGroup::updateState(newState, oldState); if (!d->currentAnimation) return; @@ -532,7 +532,7 @@ void QSequentialAnimationGroupPrivate::animationInsertedAt(int index) currentAnimationIndex = animations.indexOf(currentAnimation); if (index < currentAnimationIndex || currentLoop != 0) { - qWarning("QSequentialGroup::insertAnimationAt only supports to add animations after the current one."); + qWarning("QSequentialGroup::insertAnimation only supports to add animations after the current one."); return; //we're not affected because it is added after the current one } } diff --git a/src/corelib/animation/qsequentialanimationgroup.h b/src/corelib/animation/qsequentialanimationgroup.h index f30f851..97e7e01 100644 --- a/src/corelib/animation/qsequentialanimationgroup.h +++ b/src/corelib/animation/qsequentialanimationgroup.h @@ -65,7 +65,7 @@ public: ~QSequentialAnimationGroup(); QPauseAnimation *addPause(int msecs); - QPauseAnimation *insertPauseAt(int index, int msecs); + QPauseAnimation *insertPause(int index, int msecs); QAbstractAnimation *currentAnimation() const; int duration() const; @@ -78,7 +78,7 @@ protected: bool event(QEvent *event); void updateCurrentTime(int); - void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); void updateDirection(QAbstractAnimation::Direction direction); private: diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp index de8185b..c735778 100644 --- a/src/corelib/animation/qvariantanimation.cpp +++ b/src/corelib/animation/qvariantanimation.cpp @@ -621,8 +621,8 @@ bool QVariantAnimation::event(QEvent *event) /*! \reimp */ -void QVariantAnimation::updateState(QAbstractAnimation::State oldState, - QAbstractAnimation::State newState) +void QVariantAnimation::updateState(QAbstractAnimation::State newState, + QAbstractAnimation::State oldState) { Q_UNUSED(oldState); Q_UNUSED(newState); diff --git a/src/corelib/animation/qvariantanimation.h b/src/corelib/animation/qvariantanimation.h index bc57b1c..89d9b34 100644 --- a/src/corelib/animation/qvariantanimation.h +++ b/src/corelib/animation/qvariantanimation.h @@ -103,7 +103,7 @@ protected: bool event(QEvent *event); void updateCurrentTime(int); - void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState); + void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState); virtual void updateCurrentValue(const QVariant &value) = 0; virtual QVariant interpolated(const QVariant &from, const QVariant &to, qreal progress) const; diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 5578091..62b5409 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -1191,6 +1191,10 @@ bool qSharedBuild() \value SV_9_2 Symbian OS v9.2 \value SV_9_3 Symbian OS v9.3 \value SV_9_4 Symbian OS v9.4 + \value SV_SF_1 Symbian^1 + \value SV_SF_2 Symbian^2 + \value SV_SF_3 Symbian^3 + \value SV_SF_4 Symbian^4 \value SV_Unknown An unknown and currently unsupported platform \sa S60Version, WinVersion, MacVersion @@ -1207,6 +1211,8 @@ bool qSharedBuild() \value SV_S60_3_1 S60 3rd Edition Feature Pack 1 \value SV_S60_3_2 S60 3rd Edition Feature Pack 2 \value SV_S60_5_0 S60 5th Edition + \value SV_S60_5_1 S60 5th Edition Feature Pack 1 + \value SV_S60_5_2 S60 5th Edition Feature Pack 2 \value SV_S60_Unknown An unknown and currently unsupported platform \omitvalue SV_S60_None diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp index 15a06d7..15325ae 100644 --- a/src/corelib/global/qlibraryinfo.cpp +++ b/src/corelib/global/qlibraryinfo.cpp @@ -212,11 +212,13 @@ QLibraryInfo::buildKey() Returns the installation date for this build of Qt. The install date will usually be the last time that Qt sources were configured. */ +#ifndef QT_NO_DATESTRING QDate QLibraryInfo::buildDate() { return QDate::fromString(QString::fromLatin1(qt_configure_installation + 12), Qt::ISODate); } +#endif //QT_NO_DATESTRING /*! Returns the location specified by \a loc. diff --git a/src/corelib/global/qlibraryinfo.h b/src/corelib/global/qlibraryinfo.h index 88e8566..f65051d 100644 --- a/src/corelib/global/qlibraryinfo.h +++ b/src/corelib/global/qlibraryinfo.h @@ -60,7 +60,9 @@ public: static QString licensedProducts(); static QString buildKey(); +#ifndef QT_NO_DATESTRING static QDate buildDate(); +#endif //QT_NO_DATESTRING enum LibraryLocation { diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 134c4b8..c9b2603 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -1020,14 +1020,15 @@ bool QFile::open(OpenMode mode) \bold{Warning:} \list 1 - \o If \a fh is \c stdin, \c stdout, or \c stderr, you may not be able - to seek(). See QIODevice::isSequential() for more information. + \o If \a fh does not refer to a regular file, e.g., it is \c stdin, + \c stdout, or \c stderr, you may not be able to seek(). size() + returns \c 0 in those cases. See QIODevice::isSequential() for + more information. \o Since this function opens the file without specifying the file name, you cannot use this QFile with a QFileInfo. \endlist - \note For Windows CE you may not be able to call seek() and resize(). - Also, size() is set to \c 0. + \note For Windows CE you may not be able to call resize(). \sa close(), {qmake Variable Reference#CONFIG}{qmake Variable Reference} @@ -1064,7 +1065,7 @@ bool QFile::open(FILE *fh, OpenMode mode) if (mode & Append) { seek(size()); } else { - long pos = ftell(fh); + qint64 pos = (qint64)QT_FTELL(fh); if (pos != -1) seek(pos); } @@ -1081,7 +1082,7 @@ bool QFile::open(FILE *fh, OpenMode mode) /*! \overload - Opens the existing file descripter \a fd in the given \a mode. + Opens the existing file descriptor \a fd in the given \a mode. Returns true if successful; otherwise returns false. When a QFile is opened using this function, close() does not @@ -1092,12 +1093,13 @@ bool QFile::open(FILE *fh, OpenMode mode) are slow. If you run into performance issues, you should try to use one of the other open functions. - \warning If \a fd is 0 (\c stdin), 1 (\c stdout), or 2 (\c - stderr), you may not be able to seek(). size() is set to \c - LLONG_MAX (in \c <climits>). + \warning If \a fd is not a regular file, e.g, it is 0 (\c stdin), + 1 (\c stdout), or 2 (\c stderr), you may not be able to seek(). In + those cases, size() returns \c 0. See QIODevice::isSequential() + for more information. \warning For Windows CE you may not be able to call seek(), setSize(), - fileTime(). size() is set to \c 0. + fileTime(). size() returns \c 0. \warning Since this function opens the file without specifying the file name, you cannot use this QFile with a QFileInfo. @@ -1120,8 +1122,13 @@ bool QFile::open(int fd, OpenMode mode) } if(d->openExternalFile(mode, fd)) { QIODevice::open(mode); - if (mode & Append) + if (mode & Append) { seek(size()); + } else { + qint64 pos = (qint64)QT_LSEEK(fd, QT_OFF_T(0), SEEK_CUR); + if (pos != -1) + seek(pos); + } return true; } return false; diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index b69a5e5..d376dc7 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -132,11 +132,9 @@ void QFSFileEnginePrivate::init() #ifdef Q_OS_WIN fileAttrib = INVALID_FILE_ATTRIBUTES; fileHandle = INVALID_HANDLE_VALUE; + mapHandle = INVALID_HANDLE_VALUE; cachedFd = -1; #endif -#ifdef Q_USE_DEPRECATED_MAP_API - fileMapHandle = INVALID_HANDLE_VALUE; -#endif } /*! @@ -329,9 +327,9 @@ bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh) int ret; do { ret = QT_FSEEK(fh, 0, SEEK_END); - } while (ret == -1 && errno == EINTR); + } while (ret != 0 && errno == EINTR); - if (ret == -1) { + if (ret != 0) { q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(int(errno))); @@ -576,20 +574,23 @@ bool QFSFileEnginePrivate::seekFdFh(qint64 pos) if (lastIOCommand != QFSFileEnginePrivate::IOFlushCommand && !q->flush()) return false; + if (pos < 0 || pos != qint64(QT_OFF_T(pos))) + return false; + if (fh) { // Buffered stdlib mode. int ret; do { ret = QT_FSEEK(fh, QT_OFF_T(pos), SEEK_SET); - } while (ret == -1 && errno == EINTR); + } while (ret != 0 && errno == EINTR); - if (ret == -1) { + if (ret != 0) { q->setError(QFile::ReadError, qt_error_string(int(errno))); return false; } } else { // Unbuffered stdio mode. - if (QT_LSEEK(fd, pos, SEEK_SET) == -1) { + if (QT_LSEEK(fd, QT_OFF_T(pos), SEEK_SET) == -1) { qWarning() << "QFile::at: Cannot set file position" << pos; q->setError(QFile::PositionError, qt_error_string(errno)); return false; diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h index 66e0219..87f0737 100644 --- a/src/corelib/io/qfsfileengine_p.h +++ b/src/corelib/io/qfsfileengine_p.h @@ -110,20 +110,16 @@ public: FILE *fh; #ifdef Q_WS_WIN HANDLE fileHandle; - QHash<uchar *, QPair<int /*offset*/, HANDLE /*handle*/> > maps; + HANDLE mapHandle; + QHash<uchar *, DWORD /* offset % AllocationGranularity */> maps; mutable int cachedFd; mutable DWORD fileAttrib; #else - QHash<uchar *, QPair<int /*offset*/, int /*handle|len*/> > maps; + QHash<uchar *, QPair<int /*offset % PageSize*/, size_t /*length + offset % PageSize*/> > maps; mutable QT_STATBUF st; #endif int fd; -#ifdef Q_USE_DEPRECATED_MAP_API - void mapHandleClose(); - HANDLE fileMapHandle; -#endif - enum LastIOCommand { IOFlushCommand, diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index b0cddaa..05e6fab 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -1243,34 +1243,51 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla q->setError(QFile::PermissionsError, qt_error_string(int(EACCES))); return 0; } - if (offset < 0) { + + if (offset < 0 || offset != qint64(QT_OFF_T(offset)) + || size < 0 || size > qint64(size_t(-1))) { q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL))); return 0; } + + // If we know the mapping will extend beyond EOF, fail early to avoid + // undefined behavior. Otherwise, let mmap have its say. + if (doStat() + && (QT_OFF_T(size) > st.st_size - QT_OFF_T(offset))) + return 0; + int access = 0; if (openMode & QIODevice::ReadOnly) access |= PROT_READ; if (openMode & QIODevice::WriteOnly) access |= PROT_WRITE; - int pagesSize = getpagesize(); - int realOffset = offset / pagesSize; - int extra = offset % pagesSize; + int pageSize = getpagesize(); + int extra = offset % pageSize; + + if (size + extra > (size_t)-1) { + q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL))); + return 0; + } + + size_t realSize = (size_t)size + extra; + QT_OFF_T realOffset = QT_OFF_T(offset); + realOffset &= ~(QT_OFF_T(pageSize - 1)); #ifdef Q_OS_SYMBIAN void *mapAddress; - TRAPD(err, mapAddress = mmap((void*)0, (size_t)size + extra, - access, MAP_SHARED, nativeHandle(), realOffset * pagesSize)); + TRAPD(err, mapAddress = QT_MMAP((void*)0, realSize, + access, MAP_SHARED, nativeHandle(), realOffset)); if (err != KErrNone) { qWarning("OpenC bug: leave from mmap %d", err); mapAddress = MAP_FAILED; errno = EINVAL; } #else - void *mapAddress = mmap((void*)0, (size_t)size + extra, - access, MAP_SHARED, nativeHandle(), realOffset * pagesSize); + void *mapAddress = QT_MMAP((void*)0, realSize, + access, MAP_SHARED, nativeHandle(), realOffset); #endif if (MAP_FAILED != mapAddress) { uchar *address = extra + static_cast<uchar*>(mapAddress); - maps[address] = QPair<int,int>(extra, size); + maps[address] = QPair<int,size_t>(extra, realSize); return address; } @@ -1300,7 +1317,7 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr) } uchar *start = ptr - maps[ptr].first; - int len = maps[ptr].second; + size_t len = maps[ptr].second; if (-1 == munmap(start, len)) { q->setError(QFile::UnspecifiedError, qt_error_string(errno)); return false; diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index 898447c..a6cb5a9 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -455,17 +455,10 @@ bool QFSFileEnginePrivate::nativeClose() // Windows native mode. bool ok = true; - if ((fileHandle == INVALID_HANDLE_VALUE || !CloseHandle(fileHandle)) -#ifdef Q_USE_DEPRECATED_MAP_API - && (fileMapHandle == INVALID_HANDLE_VALUE || !CloseHandle(fileMapHandle)) -#endif - ) { + if ((fileHandle == INVALID_HANDLE_VALUE || !::CloseHandle(fileHandle))) { q->setError(QFile::UnspecifiedError, qt_error_string()); ok = false; } -#ifdef Q_USE_DEPRECATED_MAP_API - fileMapHandle = INVALID_HANDLE_VALUE; -#endif fileHandle = INVALID_HANDLE_VALUE; cachedFd = -1; // gets closed by CloseHandle above @@ -504,14 +497,30 @@ qint64 QFSFileEnginePrivate::nativeSize() const // ### Don't flush; for buffered files, we should get away with ftell. thatQ->flush(); +#if !defined(Q_OS_WINCE) + // stdlib/stdio mode. + if (fh || fd != -1) { + qint64 fileSize = _filelengthi64(fh ? QT_FILENO(fh) : fd); + if (fileSize == -1) { + fileSize = 0; + thatQ->setError(QFile::UnspecifiedError, qt_error_string(errno)); + } + return fileSize; + } +#else // Q_OS_WINCE // Buffered stdlib mode. if (fh) { QT_OFF_T oldPos = QT_FTELL(fh); QT_FSEEK(fh, 0, SEEK_END); - QT_OFF_T fileSize = QT_FTELL(fh); + qint64 fileSize = (qint64)QT_FTELL(fh); QT_FSEEK(fh, oldPos, SEEK_SET); - return qint64(fileSize); + if (fileSize == -1) { + fileSize = 0; + thatQ->setError(QFile::UnspecifiedError, qt_error_string(errno)); + } + return fileSize; } +#endif // Not-open mode, where the file name is known: We'll check the // file system directly. @@ -551,23 +560,13 @@ qint64 QFSFileEnginePrivate::nativeSize() const return 0; } - // Unbuffed stdio mode. - if(fd != -1) { -#if !defined(Q_OS_WINCE) - HANDLE handle = (HANDLE)_get_osfhandle(fd); - if (handle != INVALID_HANDLE_VALUE) { - BY_HANDLE_FILE_INFORMATION fileInfo; - if (GetFileInformationByHandle(handle, &fileInfo)) { - qint64 size = fileInfo.nFileSizeHigh; - size <<= 32; - size += fileInfo.nFileSizeLow; - return size; - } - } -#endif - thatQ->setError(QFile::UnspecifiedError, qt_error_string()); +#if defined(Q_OS_WINCE) + // Unbuffed stdio mode + if (fd != -1) { + thatQ->setError(QFile::UnspecifiedError, QLatin1String("Not implemented!")); return 0; } +#endif // Windows native mode. if (fileHandle == INVALID_HANDLE_VALUE) @@ -799,27 +798,18 @@ int QFSFileEnginePrivate::nativeHandle() const bool QFSFileEnginePrivate::nativeIsSequential() const { #if !defined(Q_OS_WINCE) - // stdlib / Windows native mode. - if (fh || fileHandle != INVALID_HANDLE_VALUE) { - if (fh == stdin || fh == stdout || fh == stderr) - return true; - - HANDLE handle = fileHandle; - if (fileHandle == INVALID_HANDLE_VALUE) { - // Rare case: using QFile::open(FILE*) to open a pipe. - handle = (HANDLE)_get_osfhandle(QT_FILENO(fh)); - return false; - } - - DWORD fileType = GetFileType(handle); - return fileType == FILE_TYPE_PIPE; - } + HANDLE handle = fileHandle; + if (fh || fd != -1) + handle = (HANDLE)_get_osfhandle(fh ? QT_FILENO(fh) : fd); + if (handle == INVALID_HANDLE_VALUE) + return false; - // stdio mode. - if (fd != -1) - return isSequentialFdFh(); -#endif + DWORD fileType = GetFileType(handle); + return (fileType == FILE_TYPE_CHAR) + || (fileType == FILE_TYPE_PIPE); +#else return false; +#endif } bool QFSFileEngine::remove() @@ -1931,42 +1921,42 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, return 0; } + if (mapHandle == INVALID_HANDLE_VALUE) { + // get handle to the file + HANDLE handle = fileHandle; - // get handle to the file - HANDLE handle = fileHandle; #ifndef Q_OS_WINCE - if (handle == INVALID_HANDLE_VALUE && fh) - handle = (HANDLE)_get_osfhandle(QT_FILENO(fh)); + if (handle == INVALID_HANDLE_VALUE && fh) + handle = (HANDLE)::_get_osfhandle(QT_FILENO(fh)); #endif #ifdef Q_USE_DEPRECATED_MAP_API - if (fileMapHandle == INVALID_HANDLE_VALUE) { nativeClose(); - fileMapHandle = CreateFileForMapping((const wchar_t*)nativeFilePath.constData(), + // handle automatically closed by kernel with mapHandle (below). + handle = ::CreateFileForMapping((const wchar_t*)nativeFilePath.constData(), GENERIC_READ | (openMode & QIODevice::WriteOnly ? GENERIC_WRITE : 0), 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - } - handle = fileMapHandle; #endif - if (handle == INVALID_HANDLE_VALUE) { - q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); - return 0; - } + if (handle == INVALID_HANDLE_VALUE) { + q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); + return 0; + } - // first create the file mapping handle - DWORD protection = (openMode & QIODevice::WriteOnly) ? PAGE_READWRITE : PAGE_READONLY; - HANDLE mapHandle = ::CreateFileMapping(handle, 0, protection, 0, 0, 0); - if (mapHandle == NULL) { - q->setError(QFile::PermissionsError, qt_error_string()); + // first create the file mapping handle + DWORD protection = (openMode & QIODevice::WriteOnly) ? PAGE_READWRITE : PAGE_READONLY; + mapHandle = ::CreateFileMapping(handle, 0, protection, 0, 0, 0); + if (mapHandle == INVALID_HANDLE_VALUE) { + q->setError(QFile::PermissionsError, qt_error_string()); #ifdef Q_USE_DEPRECATED_MAP_API - mapHandleClose(); + ::CloseHandle(handle); #endif - return 0; + return 0; + } } // setup args to map @@ -1978,17 +1968,17 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, DWORD offsetLo = offset & Q_UINT64_C(0xffffffff); SYSTEM_INFO sysinfo; ::GetSystemInfo(&sysinfo); - int mask = sysinfo.dwAllocationGranularity - 1; - int extra = offset & mask; + DWORD mask = sysinfo.dwAllocationGranularity - 1; + DWORD extra = offset & mask; if (extra) offsetLo &= ~mask; // attempt to create the map - LPVOID mapAddress = MapViewOfFile(mapHandle, access, + LPVOID mapAddress = ::MapViewOfFile(mapHandle, access, offsetHi, offsetLo, size + extra); if (mapAddress) { uchar *address = extra + static_cast<uchar*>(mapAddress); - maps[address] = QPair<int, HANDLE>(extra, mapHandle); + maps[address] = extra; return address; } @@ -2001,10 +1991,8 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, default: q->setError(QFile::UnspecifiedError, qt_error_string()); } - CloseHandle(mapHandle); -#ifdef Q_USE_DEPRECATED_MAP_API - mapHandleClose(); -#endif + + ::CloseHandle(mapHandle); return 0; } @@ -2015,32 +2003,19 @@ bool QFSFileEnginePrivate::unmap(uchar *ptr) q->setError(QFile::PermissionsError, qt_error_string(ERROR_ACCESS_DENIED)); return false; } - uchar *start = ptr - maps[ptr].first; + uchar *start = ptr - maps[ptr]; if (!UnmapViewOfFile(start)) { q->setError(QFile::PermissionsError, qt_error_string()); return false; } - if (!CloseHandle((HANDLE)maps[ptr].second)) { - q->setError(QFile::UnspecifiedError, qt_error_string()); - return false; - } maps.remove(ptr); - -#ifdef Q_USE_DEPRECATED_MAP_API - mapHandleClose(); -#endif - return true; -} - -#ifdef Q_USE_DEPRECATED_MAP_API -void QFSFileEnginePrivate::mapHandleClose() -{ if (maps.isEmpty()) { - CloseHandle(fileMapHandle); - fileMapHandle = INVALID_HANDLE_VALUE; + ::CloseHandle(mapHandle); + mapHandle = INVALID_HANDLE_VALUE; } + + return true; } -#endif QT_END_NAMESPACE diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index d13e1d1..f2e66c5 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -470,7 +470,7 @@ LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) } return 0; } else if (message == WM_TIMER) { - if (wp == ~0u) { + if (wp == ~1u) { KillTimer(d->internalHwnd, wp); int localSerialNumber = d->serialNumber; (void) d->wakeUps.fetchAndStoreRelease(0); @@ -488,7 +488,7 @@ LRESULT CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp) if (GetQueueStatus(QS_INPUT | QS_RAWINPUT | QS_TIMER) != 0) { // delay the next pass of sendPostedEvents() until we get the special // WM_TIMER, which allows all pending Windows messages to be processed - SetTimer(d->internalHwnd, ~0u, 0, 0); + SetTimer(d->internalHwnd, ~1u, 0, 0); } else { // nothing pending in the queue, let sendPostedEvents go through d->wakeUps.fetchAndStoreRelease(0); @@ -531,15 +531,16 @@ static HWND qt_create_internal_window(const QEventDispatcherWin32 *eventDispatch qWinAppInst(), // application 0); // windows creation data. + if (!wnd) { + qWarning("QEventDispatcher: Failed to create QEventDispatcherWin32 internal window: %d\n", (int)GetLastError()); + } + #ifdef GWLP_USERDATA SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)eventDispatcher); #else SetWindowLong(wnd, GWL_USERDATA, (LONG)eventDispatcher); #endif - if (!wnd) { - qWarning("QEventDispatcher: Failed to create QEventDispatcherWin32 internal window: %d\n", (int)GetLastError()); - } return wnd; } @@ -550,7 +551,7 @@ void QEventDispatcherWin32Private::registerTimer(WinTimerInfo *t) Q_Q(QEventDispatcherWin32); int ok = 0; - if (t->interval > 15 || !t->interval || !qtimeSetEvent) { + if (t->interval > 20 || !t->interval || !qtimeSetEvent) { ok = 1; if (!t->interval) // optimization for single-shot-zero-timer QCoreApplication::postEvent(q, new QZeroTimerEvent(t->timerId)); diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index cf951c9..ecf3f9c 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -1616,9 +1616,8 @@ void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transitio } void QStateMachinePrivate::handleFilteredEvent(QObject *watched, QEvent *event) -{ - Q_ASSERT(qobjectEvents.contains(watched)); - if (qobjectEvents[watched].contains(event->type())) { +{ + if (qobjectEvents.value(watched).contains(event->type())) { postInternalEvent(new QStateMachine::WrappedEvent(watched, handler->cloneEvent(event))); processEvents(DirectProcessing); } diff --git a/src/corelib/tools/qbytearraymatcher.h b/src/corelib/tools/qbytearraymatcher.h index ef46d34..3d951cf 100644 --- a/src/corelib/tools/qbytearraymatcher.h +++ b/src/corelib/tools/qbytearraymatcher.h @@ -79,17 +79,21 @@ private: QByteArray q_pattern; #ifdef Q_CC_RVCT // explicitely allow anonymous unions for RVCT to prevent compiler warnings -#pragma anon_unions +# pragma push +# pragma anon_unions #endif struct Data { uchar q_skiptable[256]; const uchar *p; int l; - }; + }; union { uint dummy[256]; Data p; }; +#ifdef Q_CC_RVCT +# pragma pop +#endif }; QT_END_NAMESPACE diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 65c3d2a..0441107 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -151,7 +151,7 @@ class QMap static inline int payload() { return sizeof(PayloadNode) - sizeof(QMapData::Node *); } static inline int alignment() { #ifdef Q_ALIGNOF - return qMax(sizeof(void*), Q_ALIGNOF(Node)); + return int(qMax(sizeof(void*), Q_ALIGNOF(Node))); #else return 0; #endif diff --git a/src/corelib/tools/qringbuffer_p.h b/src/corelib/tools/qringbuffer_p.h index c44346c..7c766cb 100644 --- a/src/corelib/tools/qringbuffer_p.h +++ b/src/corelib/tools/qringbuffer_p.h @@ -287,6 +287,33 @@ public: return -1; } + inline int indexOf(char c, int maxLength) const { + int index = 0; + int remain = qMin(size(), maxLength); + for (int i = 0; remain && i < buffers.size(); ++i) { + int start = 0; + int end = buffers.at(i).size(); + + if (i == 0) + start = head; + if (i == tailBuffer) + end = tail; + if (remain < end - start) { + end = start + remain; + remain = 0; + } else { + remain -= end - start; + } + const char *ptr = buffers.at(i).data() + start; + for (int j = start; j < end; ++j) { + if (*ptr++ == c) + return index; + ++index; + } + } + return -1; + } + inline int read(char *data, int maxLength) { int bytesToRead = qMin(size(), maxLength); int readSoFar = 0; diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 6c9a3ca..74f93a4 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -631,6 +631,7 @@ private: friend class QCharRef; friend class QTextCodec; friend class QStringRef; + friend struct QAbstractConcatenable; friend inline bool qStringComparisonHelper(const QString &s1, const char *s2); friend inline bool qStringComparisonHelper(const QStringRef &s1, const char *s2); public: diff --git a/src/corelib/tools/qstringbuilder.cpp b/src/corelib/tools/qstringbuilder.cpp index 0a13218..4a16488 100644 --- a/src/corelib/tools/qstringbuilder.cpp +++ b/src/corelib/tools/qstringbuilder.cpp @@ -41,6 +41,8 @@ #include "qstringbuilder.h" +QT_BEGIN_NAMESPACE + /*! \class QLatin1Literal \internal @@ -143,3 +145,25 @@ Converts the \c QLatin1Literal into a \c QString object. */ + +/*! \internal */ +void QAbstractConcatenable::convertFromAscii(const char *a, int len, QChar *&out) +{ +#ifndef QT_NO_TEXTCODEC + if (QString::codecForCStrings) { + QString tmp = QString::fromAscii(a); + memcpy(out, reinterpret_cast<const char *>(tmp.constData()), sizeof(QChar) * tmp.size()); + out += tmp.length(); + return; + } +#endif + if (len == -1) { + while (*a) + *out++ = QLatin1Char(*a++); + } else { + for (int i = 0; i < len - 1; ++i) + *out++ = QLatin1Char(a[i]); + } +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index efa39b5..798d097 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -66,7 +66,7 @@ public: const char *data() const { return m_data; } template <int N> - QLatin1Literal(const char (&str)[N]) + QLatin1Literal(const char (&str)[N]) : m_size(N - 1), m_data(str) {} private: @@ -74,6 +74,21 @@ private: const char *m_data; }; +struct Q_CORE_EXPORT QAbstractConcatenable +{ +protected: + static void convertFromAscii(const char *a, int len, QChar *&out); + + static inline void convertFromAscii(char a, QChar *&out) + { +#ifndef QT_NO_TEXTCODEC + if (QString::codecForCStrings) + *out++ = QChar::fromAscii(a); + else +#endif + *out++ = QLatin1Char(a); + } +}; template <typename T> struct QConcatenable {}; @@ -87,9 +102,12 @@ public: { QString s(QConcatenable< QStringBuilder<A, B> >::size(*this), Qt::Uninitialized); - + QChar *d = s.data(); QConcatenable< QStringBuilder<A, B> >::appendTo(*this, d); + // this resize is necessary since we allocate a bit too much + // when dealing with variable sized 8-bit encodings + s.resize(d - s.data()); return s; } QByteArray toLatin1() const { return QString(*this).toLatin1(); } @@ -99,13 +117,13 @@ public: }; -template <> struct QConcatenable<char> +template <> struct QConcatenable<char> : private QAbstractConcatenable { typedef char type; static int size(const char) { return 1; } static inline void appendTo(const char c, QChar *&out) { - *out++ = QLatin1Char(c); + QAbstractConcatenable::convertFromAscii(c, out); } }; @@ -170,7 +188,7 @@ template <> struct QConcatenable<QString> { const int n = a.size(); memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n); - out += n; + out += n; } }; @@ -182,53 +200,51 @@ template <> struct QConcatenable<QStringRef> { const int n = a.size(); memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n); - out += n; + out += n; } }; #ifndef QT_NO_CAST_FROM_ASCII -template <int N> struct QConcatenable<char[N]> +template <int N> struct QConcatenable<char[N]> : private QAbstractConcatenable { typedef char type[N]; - static int size(const char[N]) { return N - 1; } + static int size(const char[N]) + { + return N - 1; + } static inline void appendTo(const char a[N], QChar *&out) { - for (int i = 0; i < N - 1; ++i) - *out++ = QLatin1Char(a[i]); + QAbstractConcatenable::convertFromAscii(a, N, out); } }; -template <int N> struct QConcatenable<const char[N]> +template <int N> struct QConcatenable<const char[N]> : private QAbstractConcatenable { typedef const char type[N]; static int size(const char[N]) { return N - 1; } static inline void appendTo(const char a[N], QChar *&out) { - for (int i = 0; i < N - 1; ++i) - *out++ = QLatin1Char(a[i]); + QAbstractConcatenable::convertFromAscii(a, N, out); } }; -template <> struct QConcatenable<const char *> +template <> struct QConcatenable<const char *> : private QAbstractConcatenable { typedef char const *type; static int size(const char *a) { return qstrlen(a); } static inline void appendTo(const char *a, QChar *&out) { - while (*a) - *out++ = QLatin1Char(*a++); + QAbstractConcatenable::convertFromAscii(a, -1, out); } }; -template <> struct QConcatenable<QByteArray> +template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable { typedef QByteArray type; static int size(const QByteArray &ba) { return qstrnlen(ba.constData(), ba.size()); } static inline void appendTo(const QByteArray &ba, QChar *&out) { - const char *data = ba.constData(); - while (*data) - *out++ = QLatin1Char(*data++); + QAbstractConcatenable::convertFromAscii(ba.constData(), -1, out); } }; #endif @@ -237,7 +253,7 @@ template <typename A, typename B> struct QConcatenable< QStringBuilder<A, B> > { typedef QStringBuilder<A, B> type; - static int size(const type &p) + static int size(const type &p) { return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b); } diff --git a/src/corelib/tools/qstringmatcher.h b/src/corelib/tools/qstringmatcher.h index 0cb1312..8076098 100644 --- a/src/corelib/tools/qstringmatcher.h +++ b/src/corelib/tools/qstringmatcher.h @@ -79,7 +79,8 @@ private: Qt::CaseSensitivity q_cs; #ifdef Q_CC_RVCT // explicitely allow anonymous unions for RVCT to prevent compiler warnings -#pragma anon_unions +# pragma push +# pragma anon_unions #endif struct Data { uchar q_skiptable[256]; @@ -90,6 +91,9 @@ private: uint q_data[256]; Data p; }; +#ifdef Q_CC_RVCT +# pragma pop +#endif }; QT_END_NAMESPACE diff --git a/src/corelib/tools/qunicodetables_p.h b/src/corelib/tools/qunicodetables_p.h index e4041b4..4e9ce4d 100644 --- a/src/corelib/tools/qunicodetables_p.h +++ b/src/corelib/tools/qunicodetables_p.h @@ -114,6 +114,7 @@ namespace QUnicodeTables { Ogham, Runic, Khmer, + Nko, Inherited, ScriptCount = Inherited, Latin = Common, @@ -152,8 +153,7 @@ namespace QUnicodeTables { Balinese = Common, Cuneiform = Common, Phoenician = Common, - PhagsPa = Common, - Nko = Common + PhagsPa = Common }; enum { ScriptSentinel = 32 }; diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index c7538c3..748658d 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -1988,7 +1988,7 @@ void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook { signalHooks.insertMulti(key, hook); connect(hook.obj, SIGNAL(destroyed(QObject*)), SLOT(objectDestroyed(QObject*)), - Qt::DirectConnection); + Qt::ConnectionType(Qt::DirectConnection | Qt::UniqueConnection)); MatchRefCountHash::iterator it = matchRefCounts.find(hook.matchRule); diff --git a/src/dbus/qdbusservicewatcher.cpp b/src/dbus/qdbusservicewatcher.cpp index 115fe3e..1557b47 100644 --- a/src/dbus/qdbusservicewatcher.cpp +++ b/src/dbus/qdbusservicewatcher.cpp @@ -47,6 +47,8 @@ #include <private/qobject_p.h> +QT_BEGIN_NAMESPACE + Q_GLOBAL_STATIC_WITH_ARGS(QString, busService, (QLatin1String(DBUS_SERVICE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString, busPath, (QLatin1String(DBUS_PATH_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString, busInterface, (QLatin1String(DBUS_INTERFACE_DBUS))) @@ -371,4 +373,6 @@ void QDBusServiceWatcher::setConnection(const QDBusConnection &connection) d->setConnection(d->servicesWatched, connection, d->watchMode); } +QT_END_NAMESPACE + #include "moc_qdbusservicewatcher.cpp" diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h index 8f6d9d9..c493054 100644 --- a/src/gui/accessible/qaccessible.h +++ b/src/gui/accessible/qaccessible.h @@ -311,7 +311,8 @@ namespace QAccessible2 EditableTextInterface, ValueInterface, TableInterface, - ActionInterface + ActionInterface, + ImageInterface }; } @@ -321,6 +322,7 @@ class QAccessibleEditableTextInterface; class QAccessibleValueInterface; class QAccessibleTableInterface; class QAccessibleActionInterface; +class QAccessibleImageInterface; class Q_GUI_EXPORT QAccessibleInterface : public QAccessible { @@ -381,6 +383,9 @@ public: inline QAccessibleActionInterface *actionInterface() { return reinterpret_cast<QAccessibleActionInterface *>(cast_helper(QAccessible2::ActionInterface)); } + inline QAccessibleImageInterface *imageInterface() + { return reinterpret_cast<QAccessibleImageInterface *>(cast_helper(QAccessible2::ImageInterface)); } + private: QAccessible2Interface *cast_helper(QAccessible2::InterfaceType); }; diff --git a/src/gui/accessible/qaccessible2.cpp b/src/gui/accessible/qaccessible2.cpp index 0867368..b878cf1 100644 --- a/src/gui/accessible/qaccessible2.cpp +++ b/src/gui/accessible/qaccessible2.cpp @@ -120,6 +120,18 @@ QT_BEGIN_NAMESPACE \link http://www.linux-foundation.org/en/Accessibility/IAccessible2 IAccessible2 Specification \endlink */ +/*! + \class QAccessibleImageInterface + \ingroup accessibility + \internal + \preliminary + + \brief The QAccessibleImageInterface class implements support for + the IAccessibleImage interface. + + \link http://www.linux-foundation.org/en/Accessibility/IAccessible2 IAccessible2 Specification \endlink +*/ + QAccessibleSimpleEditableTextInterface::QAccessibleSimpleEditableTextInterface( QAccessibleInterface *accessibleInterface) : iface(accessibleInterface) diff --git a/src/gui/accessible/qaccessible2.h b/src/gui/accessible/qaccessible2.h index 435c640..ba12a7c 100644 --- a/src/gui/accessible/qaccessible2.h +++ b/src/gui/accessible/qaccessible2.h @@ -82,6 +82,7 @@ inline QAccessible2Interface *qAccessibleTextCastHelper() { return 0; } inline QAccessible2Interface *qAccessibleEditableTextCastHelper() { return 0; } inline QAccessible2Interface *qAccessibleTableCastHelper() { return 0; } inline QAccessible2Interface *qAccessibleActionCastHelper() { return 0; } +inline QAccessible2Interface *qAccessibleImageCastHelper() { return 0; } #define Q_ACCESSIBLE_OBJECT \ public: \ @@ -98,6 +99,8 @@ inline QAccessible2Interface *qAccessibleActionCastHelper() { return 0; } return qAccessibleTableCastHelper(); \ case QAccessible2::ActionInterface: \ return qAccessibleActionCastHelper(); \ + case QAccessible2::ImageInterface: \ + return qAccessibleImageCastHelper(); \ } \ return 0; \ } \ @@ -224,6 +227,16 @@ public: virtual QStringList keyBindings(int actionIndex) = 0; }; +class Q_GUI_EXPORT QAccessibleImageInterface : public QAccessible2Interface +{ +public: + inline QAccessible2Interface *qAccessibleImageCastHelper() { return this; } + + virtual QString imageDescription() = 0; + virtual QSize imageSize() = 0; + virtual QRect imagePosition(QAccessible2::CoordinateType coordType) = 0; +}; + #endif // QT_NO_ACCESSIBILITY QT_END_NAMESPACE diff --git a/src/gui/dialogs/qcolordialog_mac.mm b/src/gui/dialogs/qcolordialog_mac.mm index 9e4fdd1..5f074c0 100644 --- a/src/gui/dialogs/qcolordialog_mac.mm +++ b/src/gui/dialogs/qcolordialog_mac.mm @@ -252,15 +252,20 @@ QT_USE_NAMESPACE delete mQtColor; mQtColor = new QColor(); NSColor *color = [mColorPanel color]; - NSString *colorSpace = [color colorSpaceName]; - if (colorSpace == NSDeviceCMYKColorSpace) { - CGFloat cyan, magenta, yellow, black, alpha; + NSString *colorSpaceName = [color colorSpaceName]; + if (colorSpaceName == NSDeviceCMYKColorSpace) { + CGFloat cyan = 0, magenta = 0, yellow = 0, black = 0, alpha = 0; [color getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha]; mQtColor->setCmykF(cyan, magenta, yellow, black, alpha); - } else if (colorSpace == NSCalibratedRGBColorSpace || colorSpace == NSDeviceRGBColorSpace) { - CGFloat red, green, blue, alpha; + } else if (colorSpaceName == NSCalibratedRGBColorSpace || colorSpaceName == NSDeviceRGBColorSpace) { + CGFloat red = 0, green = 0, blue = 0, alpha = 0; [color getRed:&red green:&green blue:&blue alpha:&alpha]; mQtColor->setRgbF(red, green, blue, alpha); + } else if (colorSpaceName == NSNamedColorSpace) { + NSColor *tmpColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; + CGFloat red = 0, green = 0, blue = 0, alpha = 0; + [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha]; + mQtColor->setRgbF(red, green, blue, alpha); } else { NSColorSpace *colorSpace = [color colorSpace]; if ([colorSpace colorSpaceModel] == NSCMYKColorSpaceModel && [color numberOfComponents] == 5){ @@ -269,7 +274,7 @@ QT_USE_NAMESPACE mQtColor->setCmykF(components[0], components[1], components[2], components[3], components[4]); } else { NSColor *tmpColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; - CGFloat red, green, blue, alpha; + CGFloat red = 0, green = 0, blue = 0, alpha = 0; [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha]; mQtColor->setRgbF(red, green, blue, alpha); } @@ -319,7 +324,18 @@ QT_USE_NAMESPACE QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active); QMacCocoaAutoReleasePool pool; mDialogIsExecuting = true; - [NSApp runModalForWindow:mColorPanel]; + bool modalEnded = false; + while (!modalEnded) { + @try { + [NSApp runModalForWindow:mColorPanel]; + modalEnded = true; + } @catch (NSException *) { + // For some reason, NSColorPanel throws an exception when + // clicking on 'SelectedMenuItemColor' from the 'Developer' + // palette (tab three). + } + } + QAbstractEventDispatcher::instance()->interrupt(); if (mResultCode == NSCancelButton) mPriv->colorDialog()->reject(); diff --git a/src/gui/effects/qgraphicseffect.cpp b/src/gui/effects/qgraphicseffect.cpp index 501786d..568ff73 100644 --- a/src/gui/effects/qgraphicseffect.cpp +++ b/src/gui/effects/qgraphicseffect.cpp @@ -128,6 +128,19 @@ QT_BEGIN_NAMESPACE */ /*! + \enum QGraphicsEffectSource::PixmapPadMode + + This enum describes how much of the effect will be rendered to a pixmap + created using the pixmap() function. + + \value NoExpandPadMode The pixmap is the size of the widget or graphics item. + \value ExpandToTransparentBorderPadMode The pixmap is expanded to include + the widget or graphics item plus a transparent border. + \value ExpandToEffectRectPadMode The pixmap is expanded to include the widget + or graphics item and the effect. +*/ + +/*! \internal */ QGraphicsEffectSource::QGraphicsEffectSource(QGraphicsEffectSourcePrivate &dd, QObject *parent) @@ -264,6 +277,9 @@ bool QGraphicsEffectSource::isPixmap() const The optional \a offset parameter returns the offset where the pixmap should be painted at using the current painter. + The \a mode determines how much of the effect the pixmap will contain. + By default, the pixmap will contain the whole effect. + The returned pixmap is bound to the current painter's device rectangle when \a system is Qt::DeviceCoordinates. @@ -740,7 +756,7 @@ void QGraphicsBlurEffect::setBlurHint(QGraphicsBlurEffect::BlurHint hint) } /*! - \fn void QGraphicsBlurEffect::blurHintChanged(Qt::BlurHint hint) + \fn void QGraphicsBlurEffect::blurHintChanged(QGraphicsBlurEffect::BlurHint hint) This signal is emitted whenever the effect's blur hint changes. The \a hint parameter holds the effect's new blur hint. diff --git a/src/gui/graphicsview/qgraph_p.h b/src/gui/graphicsview/qgraph_p.h index f1fa185..0a2bf27 100644 --- a/src/gui/graphicsview/qgraph_p.h +++ b/src/gui/graphicsview/qgraph_p.h @@ -201,11 +201,6 @@ public: return l; } - void setRootVertex(Vertex *vertex) - { - userVertex = vertex; - } - QSet<Vertex*> vertices() const { QSet<Vertex *> setOfVertices; for (const_iterator it = constBegin(); it != constEnd(); ++it) { @@ -241,7 +236,7 @@ public: EdgeData *data = edgeData(v, v1); bool forward = data->from == v; if (forward) { - edges += QString::fromAscii("%1->%2 [label=\"[%3,%4,%5]\" dir=both color=\"#000000:#a0a0a0\"] \n") + edges += QString::fromAscii("\"%1\"->\"%2\" [label=\"[%3,%4,%5]\" dir=both color=\"#000000:#a0a0a0\"] \n") .arg(v->toString()) .arg(v1->toString()) .arg(data->minSize) @@ -250,17 +245,12 @@ public: ; } } - strVertices += QString::fromAscii("%1 [label=\"%2\"]\n").arg(v->toString()).arg(v->toString()); + strVertices += QString::fromAscii("\"%1\" [label=\"%2\"]\n").arg(v->toString()).arg(v->toString()); } return QString::fromAscii("%1\n%2\n").arg(strVertices).arg(edges); } #endif - Vertex *rootVertex() const - { - return userVertex; - } - protected: void createDirectedEdge(Vertex *from, Vertex *to, EdgeData *data) { @@ -286,8 +276,6 @@ protected: } private: - Vertex *userVertex; - QHash<Vertex *, QHash<Vertex *, EdgeData *> *> m_graph; }; diff --git a/src/gui/graphicsview/qgraphicsanchorlayout.cpp b/src/gui/graphicsview/qgraphicsanchorlayout.cpp index 56d70e1..872ec3c 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout.cpp @@ -83,10 +83,8 @@ \clearfloat \section1 Size Hints and Size Policies in an Anchor Layout - QGraphicsAnchorLayout respects each item's size hints and size policies. However it does - not currently respect their stretch factors. This might change in the future, so avoid - using stretch factors in anchor layouts if you want to avoid any future regressions in - behavior. + QGraphicsAnchorLayout respects each item's size hints and size policies. + Note that there are some properties of QSizePolicy that are \l{Known issues}{not respected}. \section1 Spacing within an Anchor Layout @@ -101,6 +99,21 @@ If the spacing is negative, the items will overlap to some extent. + + \section1 Known issues + There are some features that QGraphicsAnchorLayout currently does not support. + This might change in the future, so avoid using these features if you want to + avoid any future regressions in behaviour: + \list + + \o Stretch factors are not respected. + + \o QSizePolicy::ExpandFlag is not respected. + + \o Height for width is not respected. + + \endlist + \sa QGraphicsLinearLayout, QGraphicsGridLayout, QGraphicsLayout */ diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp index 41aa8aa..182594e 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.cpp @@ -61,6 +61,8 @@ QGraphicsAnchorPrivate::QGraphicsAnchorPrivate(int version) QGraphicsAnchorPrivate::~QGraphicsAnchorPrivate() { + // ### + layoutPrivate->restoreSimplifiedGraph(QGraphicsAnchorLayoutPrivate::Orientation(data->orientation)); layoutPrivate->removeAnchor(data->from, data->to); } @@ -105,7 +107,7 @@ qreal QGraphicsAnchorPrivate::spacing() const static void internalSizeHints(QSizePolicy::Policy policy, qreal minSizeHint, qreal prefSizeHint, qreal maxSizeHint, qreal *minSize, qreal *prefSize, - qreal *expSize, qreal *maxSize) + qreal *maxSize) { // minSize, prefSize and maxSize are initialized // with item's preferred Size: this is QSizePolicy::Fixed. @@ -135,11 +137,6 @@ static void internalSizeHints(QSizePolicy::Policy policy, *prefSize = *minSize; else *prefSize = prefSizeHint; - - if (policy & QSizePolicy::ExpandFlag) - *expSize = *maxSize; - else - *expSize = *prefSize; } bool AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo) @@ -154,7 +151,6 @@ bool AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo) if (isLayoutAnchor) { minSize = 0; prefSize = 0; - expSize = 0; maxSize = QWIDGETSIZE_MAX; if (isCenterAnchor) maxSize /= 2; @@ -205,8 +201,8 @@ bool AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo) } maxSizeHint = QWIDGETSIZE_MAX; } - internalSizeHints(policy, minSizeHint, prefSizeHint, maxSizeHint, - &minSize, &prefSize, &expSize, &maxSize); + internalSizeHints(policy, minSizeHint, prefSizeHint, maxSizeHint, + &minSize, &prefSize, &maxSize); // Set the anchor effective sizes to preferred. // @@ -217,7 +213,6 @@ bool AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo) // recalculate and override the values we set here. sizeAtMinimum = prefSize; sizeAtPreferred = prefSize; - sizeAtExpanding = prefSize; sizeAtMaximum = prefSize; return true; @@ -225,10 +220,20 @@ bool AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo) void ParallelAnchorData::updateChildrenSizes() { - firstEdge->sizeAtMinimum = secondEdge->sizeAtMinimum = sizeAtMinimum; - firstEdge->sizeAtPreferred = secondEdge->sizeAtPreferred = sizeAtPreferred; - firstEdge->sizeAtExpanding = secondEdge->sizeAtExpanding = sizeAtExpanding; - firstEdge->sizeAtMaximum = secondEdge->sizeAtMaximum = sizeAtMaximum; + firstEdge->sizeAtMinimum = sizeAtMinimum; + firstEdge->sizeAtPreferred = sizeAtPreferred; + firstEdge->sizeAtMaximum = sizeAtMaximum; + + const bool secondFwd = (secondEdge->from == from); + if (secondFwd) { + secondEdge->sizeAtMinimum = sizeAtMinimum; + secondEdge->sizeAtPreferred = sizeAtPreferred; + secondEdge->sizeAtMaximum = sizeAtMaximum; + } else { + secondEdge->sizeAtMinimum = -sizeAtMinimum; + secondEdge->sizeAtPreferred = -sizeAtPreferred; + secondEdge->sizeAtMaximum = -sizeAtMaximum; + } firstEdge->updateChildrenSizes(); secondEdge->updateChildrenSizes(); @@ -247,8 +252,16 @@ bool ParallelAnchorData::refreshSizeHints_helper(const QLayoutStyleInfo *styleIn return false; } - minSize = qMax(firstEdge->minSize, secondEdge->minSize); - maxSize = qMin(firstEdge->maxSize, secondEdge->maxSize); + // Account for parallel anchors where the second edge is backwards. + // We rely on the fact that a forward anchor of sizes min, pref, max is equivalent + // to a backwards anchor of size (-max, -pref, -min) + const bool secondFwd = (secondEdge->from == from); + const qreal secondMin = secondFwd ? secondEdge->minSize : -secondEdge->maxSize; + const qreal secondPref = secondFwd ? secondEdge->prefSize : -secondEdge->prefSize; + const qreal secondMax = secondFwd ? secondEdge->maxSize : -secondEdge->minSize; + + minSize = qMax(firstEdge->minSize, secondMin); + maxSize = qMin(firstEdge->maxSize, secondMax); // This condition means that the maximum size of one anchor being simplified is smaller than // the minimum size of the other anchor. The consequence is that there won't be a valid size @@ -257,16 +270,27 @@ bool ParallelAnchorData::refreshSizeHints_helper(const QLayoutStyleInfo *styleIn return false; } - expSize = qMax(firstEdge->expSize, secondEdge->expSize); - expSize = qMin(expSize, maxSize); + // The equivalent preferred Size of a parallel anchor is calculated as to + // reduce the deviation from the original preferred sizes _and_ to avoid shrinking + // items below their preferred sizes, unless strictly needed. - prefSize = qMax(firstEdge->prefSize, secondEdge->prefSize); - prefSize = qMin(prefSize, expSize); + // ### This logic only holds if all anchors in the layout are "well-behaved" in the + // following terms: + // + // - There are no negative-sized anchors + // - All sequential anchors are composed of children in the same direction as the + // sequential anchor itself + // + // With these assumptions we can grow a child knowing that no hidden items will + // have to shrink as the result of that. + // If any of these does not hold, we have a situation where the ParallelAnchor + // does not have enough information to calculate its equivalent prefSize. + prefSize = qMax(firstEdge->prefSize, secondPref); + prefSize = qMin(prefSize, maxSize); // See comment in AnchorData::refreshSizeHints() about sizeAt* values sizeAtMinimum = prefSize; sizeAtPreferred = prefSize; - sizeAtExpanding = prefSize; sizeAtMaximum = prefSize; return true; @@ -280,8 +304,7 @@ bool ParallelAnchorData::refreshSizeHints_helper(const QLayoutStyleInfo *styleIn 1 is at Maximum */ static QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> getFactor(qreal value, qreal min, - qreal pref, qreal exp, - qreal max) + qreal pref, qreal max) { QGraphicsAnchorLayoutPrivate::Interval interval; qreal lower; @@ -291,13 +314,9 @@ static QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> getFactor(qreal valu interval = QGraphicsAnchorLayoutPrivate::MinToPreferred; lower = min; upper = pref; - } else if (value < exp) { - interval = QGraphicsAnchorLayoutPrivate::PreferredToExpanding; - lower = pref; - upper = exp; } else { - interval = QGraphicsAnchorLayoutPrivate::ExpandingToMax; - lower = exp; + interval = QGraphicsAnchorLayoutPrivate::PreferredToMax; + lower = pref; upper = max; } @@ -313,7 +332,7 @@ static QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> getFactor(qreal valu static qreal interpolate(const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> &factor, qreal min, qreal pref, - qreal exp, qreal max) + qreal max) { qreal lower; qreal upper; @@ -323,12 +342,8 @@ static qreal interpolate(const QPair<QGraphicsAnchorLayoutPrivate::Interval, qre lower = min; upper = pref; break; - case QGraphicsAnchorLayoutPrivate::PreferredToExpanding: + case QGraphicsAnchorLayoutPrivate::PreferredToMax: lower = pref; - upper = exp; - break; - case QGraphicsAnchorLayoutPrivate::ExpandingToMax: - lower = exp; upper = max; break; } @@ -341,34 +356,31 @@ void SequentialAnchorData::updateChildrenSizes() // ### REMOVE ME // ### check whether we are guarantee to get those or we need to warn stuff at this // point. - Q_ASSERT(sizeAtMinimum > minSize || qFuzzyCompare(sizeAtMinimum, minSize)); - Q_ASSERT(sizeAtMinimum < maxSize || qFuzzyCompare(sizeAtMinimum, maxSize)); - Q_ASSERT(sizeAtPreferred > minSize || qFuzzyCompare(sizeAtPreferred, minSize)); - Q_ASSERT(sizeAtPreferred < maxSize || qFuzzyCompare(sizeAtPreferred, maxSize)); - Q_ASSERT(sizeAtExpanding > minSize || qFuzzyCompare(sizeAtExpanding, minSize)); - Q_ASSERT(sizeAtExpanding < maxSize || qFuzzyCompare(sizeAtExpanding, maxSize)); - Q_ASSERT(sizeAtMaximum > minSize || qFuzzyCompare(sizeAtMaximum, minSize)); - Q_ASSERT(sizeAtMaximum < maxSize || qFuzzyCompare(sizeAtMaximum, maxSize)); + Q_ASSERT(sizeAtMinimum > minSize || qAbs(sizeAtMinimum - minSize) < 0.00000001); + Q_ASSERT(sizeAtPreferred > minSize || qAbs(sizeAtPreferred - minSize) < 0.00000001); + Q_ASSERT(sizeAtMaximum > minSize || qAbs(sizeAtMaximum - minSize) < 0.00000001); + + // These may be false if this anchor was in parallel with the layout stucture + // Q_ASSERT(sizeAtMinimum < maxSize || qAbs(sizeAtMinimum - maxSize) < 0.00000001); + // Q_ASSERT(sizeAtPreferred < maxSize || qAbs(sizeAtPreferred - maxSize) < 0.00000001); + // Q_ASSERT(sizeAtMaximum < maxSize || qAbs(sizeAtMaximum - maxSize) < 0.00000001); // Band here refers if the value is in the Minimum To Preferred // band (the lower band) or the Preferred To Maximum (the upper band). const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> minFactor = - getFactor(sizeAtMinimum, minSize, prefSize, expSize, maxSize); + getFactor(sizeAtMinimum, minSize, prefSize, maxSize); const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> prefFactor = - getFactor(sizeAtPreferred, minSize, prefSize, expSize, maxSize); - const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> expFactor = - getFactor(sizeAtExpanding, minSize, prefSize, expSize, maxSize); + getFactor(sizeAtPreferred, minSize, prefSize, maxSize); const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> maxFactor = - getFactor(sizeAtMaximum, minSize, prefSize, expSize, maxSize); + getFactor(sizeAtMaximum, minSize, prefSize, maxSize); for (int i = 0; i < m_edges.count(); ++i) { AnchorData *e = m_edges.at(i); - e->sizeAtMinimum = interpolate(minFactor, e->minSize, e->prefSize, e->expSize, e->maxSize); - e->sizeAtPreferred = interpolate(prefFactor, e->minSize, e->prefSize, e->expSize, e->maxSize); - e->sizeAtExpanding = interpolate(expFactor, e->minSize, e->prefSize, e->expSize, e->maxSize); - e->sizeAtMaximum = interpolate(maxFactor, e->minSize, e->prefSize, e->expSize, e->maxSize); + e->sizeAtMinimum = interpolate(minFactor, e->minSize, e->prefSize, e->maxSize); + e->sizeAtPreferred = interpolate(prefFactor, e->minSize, e->prefSize, e->maxSize); + e->sizeAtMaximum = interpolate(maxFactor, e->minSize, e->prefSize, e->maxSize); e->updateChildrenSizes(); } @@ -384,7 +396,6 @@ bool SequentialAnchorData::refreshSizeHints_helper(const QLayoutStyleInfo *style { minSize = 0; prefSize = 0; - expSize = 0; maxSize = 0; for (int i = 0; i < m_edges.count(); ++i) { @@ -396,14 +407,12 @@ bool SequentialAnchorData::refreshSizeHints_helper(const QLayoutStyleInfo *style minSize += edge->minSize; prefSize += edge->prefSize; - expSize += edge->expSize; maxSize += edge->maxSize; } // See comment in AnchorData::refreshSizeHints() about sizeAt* values sizeAtMinimum = prefSize; sizeAtPreferred = prefSize; - sizeAtExpanding = prefSize; sizeAtMaximum = prefSize; return true; @@ -478,12 +487,15 @@ QGraphicsAnchorLayoutPrivate::QGraphicsAnchorLayoutPrivate() for (int j = 0; j < 3; ++j) { sizeHints[i][j] = -1; } - sizeAtExpanding[i] = -1; interpolationProgress[i] = -1; spacings[i] = -1; graphSimplified[i] = false; graphHasConflicts[i] = false; + + layoutFirstVertex[i] = 0; + layoutCentralVertex[i] = 0; + layoutLastVertex[i] = 0; } } @@ -526,33 +538,67 @@ inline static qreal checkAdd(qreal a, qreal b) /*! \internal - Adds \a newAnchor to the graph \a g. + Adds \a newAnchor to the graph. Returns the newAnchor itself if it could be added without further changes to the graph. If a - new parallel anchor had to be created, then returns the new parallel anchor. In case the - addition is unfeasible -- because a parallel setup is not possible, returns 0. + new parallel anchor had to be created, then returns the new parallel anchor. If a parallel anchor + had to be created and it results in an unfeasible setup, \a feasible is set to false, otherwise + true. + + Note that in the case a new parallel anchor is created, it might also take over some constraints + from its children anchors. */ -static AnchorData *addAnchorMaybeParallel(Graph<AnchorVertex, AnchorData> *g, - AnchorData *newAnchor) +AnchorData *QGraphicsAnchorLayoutPrivate::addAnchorMaybeParallel(AnchorData *newAnchor, bool *feasible) { - bool feasible = true; + Orientation orientation = Orientation(newAnchor->orientation); + Graph<AnchorVertex, AnchorData> &g = graph[orientation]; + *feasible = true; // If already exists one anchor where newAnchor is supposed to be, we create a parallel // anchor. - if (AnchorData *oldAnchor = g->takeEdge(newAnchor->from, newAnchor->to)) { + if (AnchorData *oldAnchor = g.takeEdge(newAnchor->from, newAnchor->to)) { ParallelAnchorData *parallel = new ParallelAnchorData(oldAnchor, newAnchor); + // The parallel anchor will "replace" its children anchors in + // every center constraint that they appear. + + // ### If the dependent (center) anchors had reference(s) to their constraints, we + // could avoid traversing all the itemCenterConstraints. + QList<QSimplexConstraint *> &constraints = itemCenterConstraints[orientation]; + + AnchorData *children[2] = { oldAnchor, newAnchor }; + QList<QSimplexConstraint *> *childrenConstraints[2] = { ¶llel->m_firstConstraints, + ¶llel->m_secondConstraints }; + + for (int i = 0; i < 2; ++i) { + AnchorData *child = children[i]; + QList<QSimplexConstraint *> *childConstraints = childrenConstraints[i]; + + if (!child->isCenterAnchor) + continue; + + parallel->isCenterAnchor = true; + + for (int i = 0; i < constraints.count(); ++i) { + QSimplexConstraint *c = constraints[i]; + if (c->variables.contains(child)) { + childConstraints->append(c); + qreal v = c->variables.take(child); + c->variables.insert(parallel, v); + } + } + } + // At this point we can identify that the parallel anchor is not feasible, e.g. one // anchor minimum size is bigger than the other anchor maximum size. - feasible = parallel->refreshSizeHints_helper(0, false); + *feasible = parallel->refreshSizeHints_helper(0, false); newAnchor = parallel; } - g->createEdge(newAnchor->from, newAnchor->to, newAnchor); - return feasible ? newAnchor : 0; + g.createEdge(newAnchor->from, newAnchor->to, newAnchor); + return newAnchor; } - /*! \internal @@ -656,30 +702,185 @@ bool QGraphicsAnchorLayoutPrivate::simplifyGraph(Orientation orientation) if (graphSimplified[orientation]) return true; - graphSimplified[orientation] = true; #if 0 qDebug("Simplifying Graph for %s", orientation == Horizontal ? "Horizontal" : "Vertical"); #endif - if (!graph[orientation].rootVertex()) - return true; + // Vertex simplification + if (!simplifyVertices(orientation)) { + restoreVertices(orientation); + return false; + } + // Anchor simplification bool dirty; bool feasible = true; do { dirty = simplifyGraphIteration(orientation, &feasible); } while (dirty && feasible); - if (!feasible) - graphSimplified[orientation] = false; + // Note that if we are not feasible, we fallback and make sure that the graph is fully restored + if (!feasible) { + graphSimplified[orientation] = true; + restoreSimplifiedGraph(orientation); + restoreVertices(orientation); + return false; + } + + graphSimplified[orientation] = true; + return true; +} + +static AnchorVertex *replaceVertex_helper(AnchorData *data, AnchorVertex *oldV, AnchorVertex *newV) +{ + AnchorVertex *other; + if (data->from == oldV) { + data->from = newV; + other = data->to; + } else { + data->to = newV; + other = data->from; + } + return other; +} + +bool QGraphicsAnchorLayoutPrivate::replaceVertex(Orientation orientation, AnchorVertex *oldV, + AnchorVertex *newV, const QList<AnchorData *> &edges) +{ + Graph<AnchorVertex, AnchorData> &g = graph[orientation]; + bool feasible = true; + + for (int i = 0; i < edges.count(); ++i) { + AnchorData *ad = edges[i]; + AnchorVertex *otherV = replaceVertex_helper(ad, oldV, newV); + +#if defined(QT_DEBUG) + ad->name = QString::fromAscii("%1 --to--> %2").arg(ad->from->toString()).arg(ad->to->toString()); +#endif + + bool newFeasible; + AnchorData *newAnchor = addAnchorMaybeParallel(ad, &newFeasible); + feasible &= newFeasible; + + if (newAnchor != ad) { + // A parallel was created, we mark that in the list of anchors created by vertex + // simplification. This is needed because we want to restore them in a separate step + // from the restoration of anchor simplification. + anchorsFromSimplifiedVertices[orientation].append(newAnchor); + } + + g.takeEdge(oldV, otherV); + } return feasible; } /*! \internal +*/ +bool QGraphicsAnchorLayoutPrivate::simplifyVertices(Orientation orientation) +{ + Q_Q(QGraphicsAnchorLayout); + Graph<AnchorVertex, AnchorData> &g = graph[orientation]; + + // We'll walk through vertices + QStack<AnchorVertex *> stack; + stack.push(layoutFirstVertex[orientation]); + QSet<AnchorVertex *> visited; + + while (!stack.isEmpty()) { + AnchorVertex *v = stack.pop(); + visited.insert(v); + + // Each adjacent of 'v' is a possible vertex to be merged. So we traverse all of + // them. Since once a merge is made, we might add new adjacents, and we don't want to + // pass two times through one adjacent. The 'index' is used to track our position. + QList<AnchorVertex *> adjacents = g.adjacentVertices(v); + int index = 0; + + while (index < adjacents.count()) { + AnchorVertex *next = adjacents.at(index); + index++; + + AnchorData *data = g.edgeData(v, next); + const bool bothLayoutVertices = v->m_item == q && next->m_item == q; + const bool zeroSized = !data->minSize && !data->maxSize; + + if (!bothLayoutVertices && zeroSized) { + + // Create a new vertex pair, note that we keep a list of those vertices so we can + // easily process them when restoring the graph. + AnchorVertexPair *newV = new AnchorVertexPair(v, next, data); + simplifiedVertices[orientation].append(newV); + + // Collect the anchors of both vertices, the new vertex pair will take their place + // in those anchors + const QList<AnchorVertex *> &vAdjacents = g.adjacentVertices(v); + const QList<AnchorVertex *> &nextAdjacents = g.adjacentVertices(next); + + for (int i = 0; i < vAdjacents.count(); ++i) { + AnchorVertex *adjacent = vAdjacents.at(i); + if (adjacent != next) { + AnchorData *ad = g.edgeData(v, adjacent); + newV->m_firstAnchors.append(ad); + } + } + + for (int i = 0; i < nextAdjacents.count(); ++i) { + AnchorVertex *adjacent = nextAdjacents.at(i); + if (adjacent != v) { + AnchorData *ad = g.edgeData(next, adjacent); + newV->m_secondAnchors.append(ad); + + // We'll also add new vertices to the adjacent list of the new 'v', to be + // created as a vertex pair and replace the current one. + if (!adjacents.contains(adjacent)) + adjacents.append(adjacent); + } + } + + // ### merge this loop into the ones that calculated m_firstAnchors/m_secondAnchors? + // Make newV take the place of v and next + bool feasible = replaceVertex(orientation, v, newV, newV->m_firstAnchors); + feasible &= replaceVertex(orientation, next, newV, newV->m_secondAnchors); + + // Update the layout vertex information if one of the vertices is a layout vertex. + AnchorVertex *layoutVertex = 0; + if (v->m_item == q) + layoutVertex = v; + else if (next->m_item == q) + layoutVertex = next; + + if (layoutVertex) { + // Layout vertices always have m_item == q... + newV->m_item = q; + changeLayoutVertex(orientation, layoutVertex, newV); + } + + g.takeEdge(v, next); + + // If a non-feasibility is found, we leave early and cancel the simplification + if (!feasible) + return false; + + v = newV; + visited.insert(newV); + + } else if (!visited.contains(next) && !stack.contains(next)) { + // If the adjacent is not fit for merge and it wasn't visited by the outermost + // loop, we add it to the stack. + stack.push(next); + } + } + } + + return true; +} + +/*! + \internal One iteration of the simplification algorithm. Returns true if another iteration is needed. @@ -700,7 +901,7 @@ bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(QGraphicsAnchorLayoutP QSet<AnchorVertex *> visited; QStack<QPair<AnchorVertex *, AnchorVertex *> > stack; - stack.push(qMakePair(static_cast<AnchorVertex *>(0), g.rootVertex())); + stack.push(qMakePair(static_cast<AnchorVertex *>(0), layoutFirstVertex[orientation])); QVector<AnchorVertex*> candidates; bool candidatesForward; @@ -719,7 +920,8 @@ bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(QGraphicsAnchorLayoutP // (a) it is a layout vertex, we don't simplify away the layout vertices; // (b) it does not have exactly 2 adjacents; // (c) it will change the direction of the sequence; - // (d) its next adjacent is already visited (a cycle in the graph). + // (d) its next adjacent is already visited (a cycle in the graph); + // (e) the next anchor is a center anchor. const QList<AnchorVertex *> &adjacents = g.adjacentVertices(v); const bool isLayoutVertex = v->m_item == q; @@ -742,13 +944,14 @@ bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(QGraphicsAnchorLayoutP candidatesForward = (beforeSequence == data->from); } - // This is a tricky part. We peek at the next vertex to find out + // This is a tricky part. We peek at the next vertex to find out whether // - // - whether the edge from this vertex to the next vertex has the same direction; - // - whether we already visited the next vertex. + // - the edge from this vertex to the next vertex has the same direction; + // - we already visited the next vertex; + // - the next anchor is a center. // - // Those are needed to identify (c) and (d). Note that unlike (a) and (b), we preempt - // the end of sequence by looking into the next vertex. + // Those are needed to identify the remaining end of sequence cases. Note that unlike + // (a) and (b), we preempt the end of sequence by looking into the next vertex. // Peek at the next vertex AnchorVertex *after; @@ -766,8 +969,8 @@ bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(QGraphicsAnchorLayoutP const bool willChangeDirection = (candidatesForward != (v == data->from)); const bool cycleFound = visited.contains(after); - // Now cases (c) and (d)... - endOfSequence = willChangeDirection || cycleFound; + // Now cases (c), (d) and (e)... + endOfSequence = willChangeDirection || cycleFound || data->isCenterAnchor; if (endOfSequence) { if (!willChangeDirection) { @@ -839,9 +1042,10 @@ bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(QGraphicsAnchorLayoutP // If 'beforeSequence' and 'afterSequence' already had an anchor between them, we'll // create a parallel anchor between the new sequence and the old anchor. - AnchorData *newAnchor = addAnchorMaybeParallel(&g, sequence); + bool newFeasible; + AnchorData *newAnchor = addAnchorMaybeParallel(sequence, &newFeasible); - if (!newAnchor) { + if (!newFeasible) { *feasible = false; return false; } @@ -861,48 +1065,70 @@ bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(QGraphicsAnchorLayoutP return false; } -static void restoreSimplifiedAnchor(Graph<AnchorVertex, AnchorData> &g, - AnchorData *edge, - AnchorVertex *before, - AnchorVertex *after) +void QGraphicsAnchorLayoutPrivate::restoreSimplifiedAnchor(AnchorData *edge) { - Q_ASSERT(edge->type != AnchorData::Normal); #if 0 static const char *anchortypes[] = {"Normal", "Sequential", "Parallel"}; qDebug("Restoring %s edge.", anchortypes[int(edge->type)]); #endif - if (edge->type == AnchorData::Sequential) { - SequentialAnchorData* seqEdge = static_cast<SequentialAnchorData*>(edge); - // restore the sequential anchor - AnchorVertex *prev = before; - AnchorVertex *last = after; - if (edge->from != prev) - qSwap(last, prev); - - for (int i = 0; i < seqEdge->m_edges.count(); ++i) { - AnchorVertex *v1 = (i < seqEdge->m_children.count()) ? seqEdge->m_children.at(i) : last; - AnchorData *data = seqEdge->m_edges.at(i); - if (data->type != AnchorData::Normal) { - restoreSimplifiedAnchor(g, data, prev, v1); - } else { - g.createEdge(prev, v1, data); - } - prev = v1; + + Graph<AnchorVertex, AnchorData> &g = graph[edge->orientation]; + + if (edge->type == AnchorData::Normal) { + g.createEdge(edge->from, edge->to, edge); + + } else if (edge->type == AnchorData::Sequential) { + SequentialAnchorData *sequence = static_cast<SequentialAnchorData *>(edge); + + for (int i = 0; i < sequence->m_edges.count(); ++i) { + AnchorData *data = sequence->m_edges.at(i); + restoreSimplifiedAnchor(data); } + + delete sequence; + } else if (edge->type == AnchorData::Parallel) { - ParallelAnchorData* parallelEdge = static_cast<ParallelAnchorData*>(edge); - AnchorData *parallelEdges[2] = {parallelEdge->firstEdge, - parallelEdge->secondEdge}; - for (int i = 0; i < 2; ++i) { - AnchorData *data = parallelEdges[i]; - if (data->type == AnchorData::Normal) { - g.createEdge(before, after, data); - } else { - restoreSimplifiedAnchor(g, data, before, after); - } - } + + // Skip parallel anchors that were created by vertex simplification, they will be processed + // later, when restoring vertex simplification. + // ### we could improve this check bit having a bit inside 'edge' + if (anchorsFromSimplifiedVertices[edge->orientation].contains(edge)) + return; + + ParallelAnchorData* parallel = static_cast<ParallelAnchorData*>(edge); + restoreSimplifiedConstraints(parallel); + + // ### Because of the way parallel anchors are created in the anchor simplification + // algorithm, we know that one of these will be a sequence, so it'll be safe if the other + // anchor create an edge between the same vertices as the parallel. + Q_ASSERT(parallel->firstEdge->type == AnchorData::Sequential + || parallel->secondEdge->type == AnchorData::Sequential); + restoreSimplifiedAnchor(parallel->firstEdge); + restoreSimplifiedAnchor(parallel->secondEdge); + + delete parallel; + } +} + +void QGraphicsAnchorLayoutPrivate::restoreSimplifiedConstraints(ParallelAnchorData *parallel) +{ + if (!parallel->isCenterAnchor) + return; + + for (int i = 0; i < parallel->m_firstConstraints.count(); ++i) { + QSimplexConstraint *c = parallel->m_firstConstraints.at(i); + qreal v = c->variables[parallel]; + c->variables.remove(parallel); + c->variables.insert(parallel->firstEdge, v); + } + + for (int i = 0; i < parallel->m_secondConstraints.count(); ++i) { + QSimplexConstraint *c = parallel->m_secondConstraints.at(i); + qreal v = c->variables[parallel]; + c->variables.remove(parallel); + c->variables.insert(parallel->secondEdge, v); } } @@ -917,19 +1143,93 @@ void QGraphicsAnchorLayoutPrivate::restoreSimplifiedGraph(Orientation orientatio orientation == Horizontal ? "Horizontal" : "Vertical"); #endif + // Restore anchor simplification Graph<AnchorVertex, AnchorData> &g = graph[orientation]; - QList<QPair<AnchorVertex*, AnchorVertex*> > connections = g.connections(); for (int i = 0; i < connections.count(); ++i) { AnchorVertex *v1 = connections.at(i).first; AnchorVertex *v2 = connections.at(i).second; AnchorData *edge = g.edgeData(v1, v2); - if (edge->type != AnchorData::Normal) { - AnchorData *oldEdge = g.takeEdge(v1, v2); - restoreSimplifiedAnchor(g, edge, v1, v2); - delete oldEdge; + + // We restore only sequential anchors and parallels that were not created by + // vertex simplification. + if (edge->type == AnchorData::Sequential + || (edge->type == AnchorData::Parallel && + !anchorsFromSimplifiedVertices[orientation].contains(edge))) { + + g.takeEdge(v1, v2); + restoreSimplifiedAnchor(edge); } } + + restoreVertices(orientation); +} + +void QGraphicsAnchorLayoutPrivate::restoreVertices(Orientation orientation) +{ + Q_Q(QGraphicsAnchorLayout); + + Graph<AnchorVertex, AnchorData> &g = graph[orientation]; + QList<AnchorVertexPair *> &toRestore = simplifiedVertices[orientation]; + + // We will restore the vertices in the inverse order of creation, this way we ensure that + // the vertex being restored was not wrapped by another simplification. + for (int i = toRestore.count() - 1; i >= 0; --i) { + AnchorVertexPair *pair = toRestore.at(i); + QList<AnchorVertex *> adjacents = g.adjacentVertices(pair); + + // Restore the removed edge, this will also restore both vertices 'first' and 'second' to + // the graph structure. + AnchorVertex *first = pair->m_first; + AnchorVertex *second = pair->m_second; + g.createEdge(first, second, pair->m_removedAnchor); + + // Restore the anchors for the first child vertex + for (int j = 0; j < pair->m_firstAnchors.count(); ++j) { + AnchorData *ad = pair->m_firstAnchors.at(j); + Q_ASSERT(ad->from == pair || ad->to == pair); + + replaceVertex_helper(ad, pair, first); + g.createEdge(ad->from, ad->to, ad); + } + + // Restore the anchors for the second child vertex + for (int j = 0; j < pair->m_secondAnchors.count(); ++j) { + AnchorData *ad = pair->m_secondAnchors.at(j); + Q_ASSERT(ad->from == pair || ad->to == pair); + + replaceVertex_helper(ad, pair, second); + g.createEdge(ad->from, ad->to, ad); + } + + for (int j = 0; j < adjacents.count(); ++j) { + g.takeEdge(pair, adjacents.at(j)); + } + + // The pair simplified a layout vertex, so place back the correct vertex in the variable + // that track layout vertices + if (pair->m_item == q) { + AnchorVertex *layoutVertex = first->m_item == q ? first : second; + Q_ASSERT(layoutVertex->m_item == q); + changeLayoutVertex(orientation, pair, layoutVertex); + } + + delete pair; + } + toRestore.clear(); + + // The restoration process for vertex simplification also restored the effect of the + // parallel anchors created during vertex simplification, so we just need to restore + // the constraints in case of parallels that contain center anchors. For the same + // reason as above, order matters here. + QList<AnchorData *> ¶llelAnchors = anchorsFromSimplifiedVertices[orientation]; + + for (int i = parallelAnchors.count() - 1; i >= 0; --i) { + ParallelAnchorData *parallel = static_cast<ParallelAnchorData *>(parallelAnchors.at(i)); + restoreSimplifiedConstraints(parallel); + delete parallel; + } + parallelAnchors.clear(); } QGraphicsAnchorLayoutPrivate::Orientation @@ -959,9 +1259,10 @@ void QGraphicsAnchorLayoutPrivate::createLayoutEdges() data->maxSize = QWIDGETSIZE_MAX; data->skipInPreferred = 1; - // Set the Layout Left edge as the root of the horizontal graph. - AnchorVertex *v = internalVertex(layout, Qt::AnchorLeft); - graph[Horizontal].setRootVertex(v); + // Save a reference to layout vertices + layoutFirstVertex[Horizontal] = internalVertex(layout, Qt::AnchorLeft); + layoutCentralVertex[Horizontal] = 0; + layoutLastVertex[Horizontal] = internalVertex(layout, Qt::AnchorRight); // Vertical data = new AnchorData; @@ -970,17 +1271,18 @@ void QGraphicsAnchorLayoutPrivate::createLayoutEdges() data->maxSize = QWIDGETSIZE_MAX; data->skipInPreferred = 1; - // Set the Layout Top edge as the root of the vertical graph. - v = internalVertex(layout, Qt::AnchorTop); - graph[Vertical].setRootVertex(v); + // Save a reference to layout vertices + layoutFirstVertex[Vertical] = internalVertex(layout, Qt::AnchorTop); + layoutCentralVertex[Vertical] = 0; + layoutLastVertex[Vertical] = internalVertex(layout, Qt::AnchorBottom); } void QGraphicsAnchorLayoutPrivate::deleteLayoutEdges() { Q_Q(QGraphicsAnchorLayout); - Q_ASSERT(internalVertex(q, Qt::AnchorHorizontalCenter) == NULL); - Q_ASSERT(internalVertex(q, Qt::AnchorVerticalCenter) == NULL); + Q_ASSERT(!internalVertex(q, Qt::AnchorHorizontalCenter)); + Q_ASSERT(!internalVertex(q, Qt::AnchorVerticalCenter)); removeAnchor_helper(internalVertex(q, Qt::AnchorLeft), internalVertex(q, Qt::AnchorRight)); @@ -1019,6 +1321,8 @@ void QGraphicsAnchorLayoutPrivate::createItemEdges(QGraphicsLayoutItem *item) void QGraphicsAnchorLayoutPrivate::createCenterAnchors( QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge) { + Q_Q(QGraphicsAnchorLayout); + Orientation orientation; switch (centerEdge) { case Qt::AnchorHorizontalCenter: @@ -1061,24 +1365,32 @@ void QGraphicsAnchorLayoutPrivate::createCenterAnchors( c->variables.insert(data, 1.0); addAnchor_helper(item, firstEdge, item, centerEdge, data); data->isCenterAnchor = true; + data->dependency = AnchorData::Master; data->refreshSizeHints(0); data = new AnchorData; c->variables.insert(data, -1.0); addAnchor_helper(item, centerEdge, item, lastEdge, data); data->isCenterAnchor = true; + data->dependency = AnchorData::Slave; data->refreshSizeHints(0); itemCenterConstraints[orientation].append(c); // Remove old one removeAnchor_helper(first, last); + + if (item == q) { + layoutCentralVertex[orientation] = internalVertex(q, centerEdge); + } } void QGraphicsAnchorLayoutPrivate::removeCenterAnchors( QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge, bool substitute) { + Q_Q(QGraphicsAnchorLayout); + Orientation orientation; switch (centerEdge) { case Qt::AnchorHorizontalCenter: @@ -1120,7 +1432,7 @@ void QGraphicsAnchorLayoutPrivate::removeCenterAnchors( AnchorData *oldData = g.edgeData(first, center); // Remove center constraint for (int i = itemCenterConstraints[orientation].count() - 1; i >= 0; --i) { - if (itemCenterConstraints[orientation][i]->variables.contains(oldData)) { + if (itemCenterConstraints[orientation].at(i)->variables.contains(oldData)) { delete itemCenterConstraints[orientation].takeAt(i); break; } @@ -1151,6 +1463,10 @@ void QGraphicsAnchorLayoutPrivate::removeCenterAnchors( // by this time, the center vertex is deleted and merged into a non-centered internal anchor removeAnchor_helper(first, internalVertex(item, lastEdge)); } + + if (item == q) { + layoutCentralVertex[orientation] = 0; + } } @@ -1180,7 +1496,7 @@ void QGraphicsAnchorLayoutPrivate::removeCenterConstraints(QGraphicsLayoutItem * // Look for our anchor in all item center constraints, then remove it for (int i = 0; i < itemCenterConstraints[orientation].size(); ++i) { - if (itemCenterConstraints[orientation][i]->variables.contains(internalAnchor)) { + if (itemCenterConstraints[orientation].at(i)->variables.contains(internalAnchor)) { delete itemCenterConstraints[orientation].takeAt(i); break; } @@ -1690,7 +2006,7 @@ QList<AnchorData *> getVariables(QList<QSimplexConstraint *> constraints) { QSet<AnchorData *> variableSet; for (int i = 0; i < constraints.count(); ++i) { - const QSimplexConstraint *c = constraints[i]; + const QSimplexConstraint *c = constraints.at(i); foreach (QSimplexVariable *var, c->variables.keys()) { variableSet += static_cast<AnchorData *>(var); } @@ -1724,12 +2040,19 @@ QList<AnchorData *> getVariables(QList<QSimplexConstraint *> constraints) void QGraphicsAnchorLayoutPrivate::calculateGraphs( QGraphicsAnchorLayoutPrivate::Orientation orientation) { - Q_Q(QGraphicsAnchorLayout); - #if defined(QT_DEBUG) || defined(Q_AUTOTEST_EXPORT) lastCalculationUsedSimplex[orientation] = false; #endif + // ### This is necessary because now we do vertex simplification, we still don't know + // differentiate between invalidate()s that doesn't need resimplification and those which + // need. For example, when size hint of an item changes, this may cause an anchor to reach 0 or to + // leave 0 and get a size. In both cases we need resimplify. + // + // ### one possible solution would be tracking all the 0-sized anchors, if this set change, we need + // resimplify. + restoreSimplifiedGraph(orientation); + // Reset the nominal sizes of each anchor based on the current item sizes. This function // works with both simplified and non-simplified graphs, so it'll work when the // simplification is going to be reused. @@ -1768,12 +2091,12 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( // Now run the simplex solver to calculate Minimum, Preferred and Maximum sizes // of the "trunk" set of constraints and variables. // ### does trunk always exist? empty = trunk is the layout left->center->right - QList<QSimplexConstraint *> trunkConstraints = parts[0]; + QList<QSimplexConstraint *> trunkConstraints = parts.at(0); QList<AnchorData *> trunkVariables = getVariables(trunkConstraints); // For minimum and maximum, use the path between the two layout sides as the // objective function. - AnchorVertex *v = internalVertex(q, pickEdge(Qt::AnchorRight, orientation)); + AnchorVertex *v = layoutLastVertex[orientation]; GraphPath trunkPath = graphPaths[orientation].value(v); bool feasible = calculateTrunk(orientation, trunkPath, trunkConstraints, trunkVariables); @@ -1787,7 +2110,7 @@ void QGraphicsAnchorLayoutPrivate::calculateGraphs( if (!feasible) break; - QList<QSimplexConstraint *> partConstraints = parts[i]; + QList<QSimplexConstraint *> partConstraints = parts.at(i); QList<AnchorData *> partVariables = getVariables(partConstraints); Q_ASSERT(!partVariables.isEmpty()); feasible &= calculateNonTrunk(partConstraints, partVariables); @@ -1836,27 +2159,19 @@ bool QGraphicsAnchorLayoutPrivate::calculateTrunk(Orientation orientation, const if (feasible) { solvePreferred(allConstraints, variables); - // Note that we don't include the sizeHintConstraints, since they - // have a different logic for solveExpanding(). - solveExpanding(constraints, variables); - - // Calculate and set the preferred and expanding sizes for the layout, + // Calculate and set the preferred size for the layout, // from the edge sizes that were calculated above. qreal pref(0.0); - qreal expanding(0.0); foreach (const AnchorData *ad, path.positives) { pref += ad->sizeAtPreferred; - expanding += ad->sizeAtExpanding; } foreach (const AnchorData *ad, path.negatives) { pref -= ad->sizeAtPreferred; - expanding -= ad->sizeAtExpanding; } sizeHints[orientation][Qt::MinimumSize] = min; sizeHints[orientation][Qt::PreferredSize] = pref; sizeHints[orientation][Qt::MaximumSize] = max; - sizeAtExpanding[orientation] = expanding; } qDeleteAll(sizeHintConstraints); @@ -1870,13 +2185,11 @@ bool QGraphicsAnchorLayoutPrivate::calculateTrunk(Orientation orientation, const AnchorData *ad = path.positives.toList()[0]; ad->sizeAtMinimum = ad->minSize; ad->sizeAtPreferred = ad->prefSize; - ad->sizeAtExpanding = ad->expSize; ad->sizeAtMaximum = ad->maxSize; sizeHints[orientation][Qt::MinimumSize] = ad->sizeAtMinimum; sizeHints[orientation][Qt::PreferredSize] = ad->sizeAtPreferred; sizeHints[orientation][Qt::MaximumSize] = ad->sizeAtMaximum; - sizeAtExpanding[orientation] = ad->sizeAtExpanding; } #if defined(QT_DEBUG) || defined(Q_AUTOTEST_EXPORT) @@ -1899,10 +2212,9 @@ bool QGraphicsAnchorLayoutPrivate::calculateNonTrunk(const QList<QSimplexConstra // Propagate size at preferred to other sizes. Semi-floats always will be // in their sizeAtPreferred. for (int j = 0; j < variables.count(); ++j) { - AnchorData *ad = variables[j]; + AnchorData *ad = variables.at(j); Q_ASSERT(ad); ad->sizeAtMinimum = ad->sizeAtPreferred; - ad->sizeAtExpanding = ad->sizeAtPreferred; ad->sizeAtMaximum = ad->sizeAtPreferred; } } @@ -1955,7 +2267,7 @@ void QGraphicsAnchorLayoutPrivate::findPaths(Orientation orientation) QSet<AnchorData *> visited; - AnchorVertex *root = graph[orientation].rootVertex(); + AnchorVertex *root = layoutFirstVertex[orientation]; graphPaths[orientation].insert(root, GraphPath()); @@ -2013,7 +2325,7 @@ void QGraphicsAnchorLayoutPrivate::constraintsFromPaths(Orientation orientation) QList<GraphPath> pathsToVertex = graphPaths[orientation].values(vertex); for (int i = 1; i < valueCount; ++i) { constraints[orientation] += \ - pathsToVertex[0].constraint(pathsToVertex[i]); + pathsToVertex[0].constraint(pathsToVertex.at(i)); } } } @@ -2041,9 +2353,37 @@ void QGraphicsAnchorLayoutPrivate::updateAnchorSizes(Orientation orientation) QList<QSimplexConstraint *> QGraphicsAnchorLayoutPrivate::constraintsFromSizeHints( const QList<AnchorData *> &anchors) { + if (anchors.isEmpty()) + return QList<QSimplexConstraint *>(); + + // Look for the layout edge. That can be either the first half in case the + // layout is split in two, or the whole layout anchor. + Orientation orient = Orientation(anchors.first()->orientation); + AnchorData *layoutEdge = 0; + if (layoutCentralVertex[orient]) { + layoutEdge = graph[orient].edgeData(layoutFirstVertex[orient], layoutCentralVertex[orient]); + } else { + layoutEdge = graph[orient].edgeData(layoutFirstVertex[orient], layoutLastVertex[orient]); + + // If maxSize is less then "infinite", that means there are other anchors + // grouped together with this one. We can't ignore its maximum value so we + // set back the variable to NULL to prevent the continue condition from being + // satisfied in the loop below. + if (layoutEdge->maxSize < QWIDGETSIZE_MAX) + layoutEdge = 0; + } + + // For each variable, create constraints based on size hints QList<QSimplexConstraint *> anchorConstraints; + bool unboundedProblem = true; for (int i = 0; i < anchors.size(); ++i) { - AnchorData *ad = anchors[i]; + AnchorData *ad = anchors.at(i); + + // Anchors that have their size directly linked to another one don't need constraints + // For exammple, the second half of an item has exactly the same size as the first half + // thus constraining the latter is enough. + if (ad->dependency == AnchorData::Slave) + continue; if ((ad->minSize == ad->maxSize) || qFuzzyCompare(ad->minSize, ad->maxSize)) { QSimplexConstraint *c = new QSimplexConstraint; @@ -2051,6 +2391,7 @@ QList<QSimplexConstraint *> QGraphicsAnchorLayoutPrivate::constraintsFromSizeHin c->constant = ad->minSize; c->ratio = QSimplexConstraint::Equal; anchorConstraints += c; + unboundedProblem = false; } else { QSimplexConstraint *c = new QSimplexConstraint; c->variables.insert(ad, 1.0); @@ -2058,14 +2399,30 @@ QList<QSimplexConstraint *> QGraphicsAnchorLayoutPrivate::constraintsFromSizeHin c->ratio = QSimplexConstraint::MoreOrEqual; anchorConstraints += c; + // We avoid adding restrictions to the layout internal anchors. That's + // to prevent unnecessary fair distribution from happening due to this + // artificial restriction. + if (ad == layoutEdge) + continue; + c = new QSimplexConstraint; c->variables.insert(ad, 1.0); c->constant = ad->maxSize; c->ratio = QSimplexConstraint::LessOrEqual; anchorConstraints += c; + unboundedProblem = false; } } + // If no upper boundary restriction was added, add one to avoid unbounded problem + if (unboundedProblem) { + QSimplexConstraint *c = new QSimplexConstraint; + c->variables.insert(layoutEdge, 1.0); + c->constant = QWIDGETSIZE_MAX; + c->ratio = QSimplexConstraint::LessOrEqual; + anchorConstraints += c; + } + return anchorConstraints; } @@ -2075,38 +2432,26 @@ QList<QSimplexConstraint *> QGraphicsAnchorLayoutPrivate::constraintsFromSizeHin QList< QList<QSimplexConstraint *> > QGraphicsAnchorLayoutPrivate::getGraphParts(Orientation orientation) { - Q_Q(QGraphicsAnchorLayout); + Q_ASSERT(layoutFirstVertex[orientation] && layoutLastVertex[orientation]); - // Find layout vertices and edges for the current orientation. - AnchorVertex *layoutFirstVertex = \ - internalVertex(q, pickEdge(Qt::AnchorLeft, orientation)); - - AnchorVertex *layoutCentralVertex = \ - internalVertex(q, pickEdge(Qt::AnchorHorizontalCenter, orientation)); - - AnchorVertex *layoutLastVertex = \ - internalVertex(q, pickEdge(Qt::AnchorRight, orientation)); - - Q_ASSERT(layoutFirstVertex && layoutLastVertex); - - AnchorData *edgeL1 = NULL; - AnchorData *edgeL2 = NULL; + AnchorData *edgeL1 = 0; + AnchorData *edgeL2 = 0; // The layout may have a single anchor between Left and Right or two half anchors // passing through the center - if (layoutCentralVertex) { - edgeL1 = graph[orientation].edgeData(layoutFirstVertex, layoutCentralVertex); - edgeL2 = graph[orientation].edgeData(layoutCentralVertex, layoutLastVertex); + if (layoutCentralVertex[orientation]) { + edgeL1 = graph[orientation].edgeData(layoutFirstVertex[orientation], layoutCentralVertex[orientation]); + edgeL2 = graph[orientation].edgeData(layoutCentralVertex[orientation], layoutLastVertex[orientation]); } else { - edgeL1 = graph[orientation].edgeData(layoutFirstVertex, layoutLastVertex); + edgeL1 = graph[orientation].edgeData(layoutFirstVertex[orientation], layoutLastVertex[orientation]); } QLinkedList<QSimplexConstraint *> remainingConstraints; for (int i = 0; i < constraints[orientation].count(); ++i) { - remainingConstraints += constraints[orientation][i]; + remainingConstraints += constraints[orientation].at(i); } for (int i = 0; i < itemCenterConstraints[orientation].count(); ++i) { - remainingConstraints += itemCenterConstraints[orientation][i]; + remainingConstraints += itemCenterConstraints[orientation].at(i); } QList<QSimplexConstraint *> trunkConstraints; @@ -2276,6 +2621,21 @@ void QGraphicsAnchorLayoutPrivate::setItemsGeometries(const QRectF &geom) } /*! + \internal + + Fill the distance in the vertex and in the sub-vertices if its a combined vertex. +*/ +static void setVertexDistance(AnchorVertex *v, qreal distance) +{ + v->distance = distance; + if (v->m_type == AnchorVertex::Pair) { + AnchorVertexPair *pair = static_cast<AnchorVertexPair *>(v); + setVertexDistance(pair->m_first, distance); + setVertexDistance(pair->m_second, distance); + } +} + +/*! \internal Calculate the position of each vertex based on the paths to each of @@ -2288,9 +2648,9 @@ void QGraphicsAnchorLayoutPrivate::calculateVertexPositions( QSet<AnchorVertex *> visited; // Get root vertex - AnchorVertex *root = graph[orientation].rootVertex(); + AnchorVertex *root = layoutFirstVertex[orientation]; - root->distance = 0; + setVertexDistance(root, 0); visited.insert(root); // Add initial edges to the queue @@ -2314,7 +2674,7 @@ void QGraphicsAnchorLayoutPrivate::calculateVertexPositions( continue; visited.insert(pair.second); - interpolateEdge(pair.first, edge, orientation); + interpolateEdge(pair.first, edge); QList<AnchorVertex *> adjacents = graph[orientation].adjacentVertices(pair.second); for (int i = 0; i < adjacents.count(); ++i) { @@ -2343,7 +2703,6 @@ void QGraphicsAnchorLayoutPrivate::setupEdgesInterpolation( result = getFactor(current, sizeHints[orientation][Qt::MinimumSize], sizeHints[orientation][Qt::PreferredSize], - sizeAtExpanding[orientation], sizeHints[orientation][Qt::MaximumSize]); interpolationInterval[orientation] = result.first; @@ -2358,7 +2717,6 @@ void QGraphicsAnchorLayoutPrivate::setupEdgesInterpolation( - minimum size, - preferred size, - - size when all expanding anchors are expanded, - maximum size. These three key values are calculated in advance using linear @@ -2370,36 +2728,32 @@ void QGraphicsAnchorLayoutPrivate::setupEdgesInterpolation( vertices to be initalized, so it calls specialized functions that will recurse back to interpolateEdge(). */ -void QGraphicsAnchorLayoutPrivate::interpolateEdge(AnchorVertex *base, - AnchorData *edge, - Orientation orientation) +void QGraphicsAnchorLayoutPrivate::interpolateEdge(AnchorVertex *base, AnchorData *edge) { + const Orientation orientation = Orientation(edge->orientation); const QPair<Interval, qreal> factor(interpolationInterval[orientation], interpolationProgress[orientation]); qreal edgeDistance = interpolate(factor, edge->sizeAtMinimum, edge->sizeAtPreferred, - edge->sizeAtExpanding, edge->sizeAtMaximum); + edge->sizeAtMaximum); Q_ASSERT(edge->from == base || edge->to == base); - if (edge->from == base) - edge->to->distance = base->distance + edgeDistance; - else - edge->from->distance = base->distance - edgeDistance; + // Calculate the distance for the vertex opposite to the base + if (edge->from == base) { + setVertexDistance(edge->to, base->distance + edgeDistance); + } else { + setVertexDistance(edge->from, base->distance - edgeDistance); + } // Process child anchors if (edge->type == AnchorData::Sequential) - interpolateSequentialEdges(edge->from, - static_cast<SequentialAnchorData *>(edge), - orientation); + interpolateSequentialEdges(static_cast<SequentialAnchorData *>(edge)); else if (edge->type == AnchorData::Parallel) - interpolateParallelEdges(edge->from, - static_cast<ParallelAnchorData *>(edge), - orientation); + interpolateParallelEdges(static_cast<ParallelAnchorData *>(edge)); } -void QGraphicsAnchorLayoutPrivate::interpolateParallelEdges( - AnchorVertex *base, ParallelAnchorData *data, Orientation orientation) +void QGraphicsAnchorLayoutPrivate::interpolateParallelEdges(ParallelAnchorData *data) { // In parallels the boundary vertices are already calculate, we // just need to look for sequential groups inside, because only @@ -2407,46 +2761,44 @@ void QGraphicsAnchorLayoutPrivate::interpolateParallelEdges( // First edge if (data->firstEdge->type == AnchorData::Sequential) - interpolateSequentialEdges(base, - static_cast<SequentialAnchorData *>(data->firstEdge), - orientation); + interpolateSequentialEdges(static_cast<SequentialAnchorData *>(data->firstEdge)); else if (data->firstEdge->type == AnchorData::Parallel) - interpolateParallelEdges(base, - static_cast<ParallelAnchorData *>(data->firstEdge), - orientation); + interpolateParallelEdges(static_cast<ParallelAnchorData *>(data->firstEdge)); // Second edge if (data->secondEdge->type == AnchorData::Sequential) - interpolateSequentialEdges(base, - static_cast<SequentialAnchorData *>(data->secondEdge), - orientation); + interpolateSequentialEdges(static_cast<SequentialAnchorData *>(data->secondEdge)); else if (data->secondEdge->type == AnchorData::Parallel) - interpolateParallelEdges(base, - static_cast<ParallelAnchorData *>(data->secondEdge), - orientation); + interpolateParallelEdges(static_cast<ParallelAnchorData *>(data->secondEdge)); } -void QGraphicsAnchorLayoutPrivate::interpolateSequentialEdges( - AnchorVertex *base, SequentialAnchorData *data, Orientation orientation) +void QGraphicsAnchorLayoutPrivate::interpolateSequentialEdges(SequentialAnchorData *data) { - AnchorVertex *prev = base; + // This method is supposed to handle any sequential anchor, even out-of-order + // ones. However, in the current QGAL implementation we should get only the + // well behaved ones. + Q_ASSERT(data->m_edges.first()->from == data->from); + Q_ASSERT(data->m_edges.last()->to == data->to); - // ### I'm not sure whether this assumption is safe. If not, - // consider that m_edges.last() could be used instead (so - // at(0) would be the one to be treated specially). - Q_ASSERT(base == data->m_edges.at(0)->to || base == data->m_edges.at(0)->from); + // At this point, the two outter vertices already have their distance + // calculated. + // We use the first as the base to calculate the internal ones + + AnchorVertex *prev = data->from; - // Skip the last for (int i = 0; i < data->m_edges.count() - 1; ++i) { - AnchorData *child = data->m_edges.at(i); - interpolateEdge(prev, child, orientation); - prev = child->to; + AnchorData *edge = data->m_edges.at(i); + interpolateEdge(prev, edge); + + // Use the recently calculated vertex as the base for the next one + const bool edgeIsForward = (edge->from == prev); + prev = edgeIsForward ? edge->to : edge->from; } // Treat the last specially, since we already calculated it's end // vertex, so it's only interesting if it's a complex one if (data->m_edges.last()->type != AnchorData::Normal) - interpolateEdge(prev, data->m_edges.last(), orientation); + interpolateEdge(prev, data->m_edges.last()); } bool QGraphicsAnchorLayoutPrivate::solveMinMax(const QList<QSimplexConstraint *> &constraints, @@ -2472,9 +2824,10 @@ bool QGraphicsAnchorLayoutPrivate::solveMinMax(const QList<QSimplexConstraint *> // Save sizeAtMinimum results QList<AnchorData *> variables = getVariables(constraints); for (int i = 0; i < variables.size(); ++i) { - AnchorData *ad = static_cast<AnchorData *>(variables[i]); - Q_ASSERT(ad->result >= ad->minSize || qFuzzyCompare(ad->result, ad->minSize)); + AnchorData *ad = static_cast<AnchorData *>(variables.at(i)); ad->sizeAtMinimum = ad->result; + Q_ASSERT(ad->sizeAtMinimum >= ad->minSize || + qAbs(ad->sizeAtMinimum - ad->minSize) < 0.00000001); } // Calculate maximum values @@ -2482,9 +2835,10 @@ bool QGraphicsAnchorLayoutPrivate::solveMinMax(const QList<QSimplexConstraint *> // Save sizeAtMaximum results for (int i = 0; i < variables.size(); ++i) { - AnchorData *ad = static_cast<AnchorData *>(variables[i]); - Q_ASSERT(ad->result <= ad->maxSize || qFuzzyCompare(ad->result, ad->maxSize)); + AnchorData *ad = static_cast<AnchorData *>(variables.at(i)); ad->sizeAtMaximum = ad->result; + // Q_ASSERT(ad->sizeAtMaximum <= ad->maxSize || + // qAbs(ad->sizeAtMaximum - ad->maxSize) < 0.00000001); } } return feasible; @@ -2515,7 +2869,7 @@ bool QGraphicsAnchorLayoutPrivate::solvePreferred(const QList<QSimplexConstraint // A + A_shrinker - A_grower = A_pref // for (int i = 0; i < variables.size(); ++i) { - AnchorData *ad = variables[i]; + AnchorData *ad = variables.at(i); if (ad->skipInPreferred) continue; @@ -2546,7 +2900,7 @@ bool QGraphicsAnchorLayoutPrivate::solvePreferred(const QList<QSimplexConstraint // Save sizeAtPreferred results for (int i = 0; i < variables.size(); ++i) { - AnchorData *ad = variables[i]; + AnchorData *ad = variables.at(i); ad->sizeAtPreferred = ad->result; } @@ -2563,139 +2917,6 @@ bool QGraphicsAnchorLayoutPrivate::solvePreferred(const QList<QSimplexConstraint /*! \internal - Calculate the "expanding" keyframe - - This new keyframe sits between the already existing sizeAtPreferred and - sizeAtMaximum keyframes. Its goal is to modify the interpolation between - the latter as to respect the "expanding" size policy of some anchors. - - Previously all items would be subject to a linear interpolation between - sizeAtPreferred and sizeAtMaximum values. This will change now, the - expanding anchors will change their size before the others. To calculate - this keyframe we use the following logic: - - 1) Ask each anchor for their desired expanding size (ad->expSize), this - value depends on the anchor expanding property in the following way: - - - Expanding normal anchors want to grow towards their maximum size - - Non-expanding normal anchors want to remain at their preferred size. - - Sequential anchors wants to grow towards a size that is calculated by: - summarizing it's child anchors, where it will use preferred size for non-expanding anchors - and maximum size for expanding anchors. - - Parallel anchors want to grow towards the smallest maximum size of all the expanding anchors. - - 2) Clamp their desired values to the value they assume in the neighbour - keyframes (sizeAtPreferred and sizeAtExpanding) - - 3) Run simplex with a setup that ensures the following: - - a. Anchors will change their value from their sizeAtPreferred towards - their sizeAtMaximum as much as required to ensure that ALL anchors - reach their respective "desired" expanding sizes. - - b. No anchors will change their value beyond what is NEEDED to satisfy - the requirement above. - - The final result is that, at the "expanding" keyframe expanding anchors - will grow and take with them all anchors that are parallel to them. - However, non-expanding anchors will remain at their preferred size unless - they are forced to grow by a parallel expanding anchor. - - Note: For anchors where the sizeAtPreferred is bigger than sizeAtMaximum, - the visual effect when the layout grows from its preferred size is - the following: Expanding anchors will keep their size while non - expanding ones will shrink. Only after non-expanding anchors have - shrinked all the way, the expanding anchors will start to shrink too. -*/ -void QGraphicsAnchorLayoutPrivate::solveExpanding(const QList<QSimplexConstraint *> &constraints, - const QList<AnchorData *> &variables) -{ - QList<QSimplexConstraint *> itemConstraints; - QSimplexConstraint *objective = new QSimplexConstraint; - bool hasExpanding = false; - - // Construct the simplex constraints and objective - for (int i = 0; i < variables.size(); ++i) { - // For each anchor - AnchorData *ad = variables[i]; - - // Clamp the desired expanding size - qreal upperBoundary = qMax(ad->sizeAtPreferred, ad->sizeAtMaximum); - qreal lowerBoundary = qMin(ad->sizeAtPreferred, ad->sizeAtMaximum); - qreal boundedExpSize = qBound(lowerBoundary, ad->expSize, upperBoundary); - - // Expanding anchors are those that want to move from their preferred size - if (boundedExpSize != ad->sizeAtPreferred) - hasExpanding = true; - - // Lock anchor between boundedExpSize and sizeAtMaximum (ensure 3.a) - if (boundedExpSize == ad->sizeAtMaximum || qFuzzyCompare(boundedExpSize, ad->sizeAtMaximum)) { - // The interval has only one possible value, we can use an "Equal" - // constraint and don't need to add this variable to the objective. - QSimplexConstraint *itemC = new QSimplexConstraint; - itemC->ratio = QSimplexConstraint::Equal; - itemC->variables.insert(ad, 1.0); - itemC->constant = boundedExpSize; - itemConstraints << itemC; - } else { - // Add MoreOrEqual and LessOrEqual constraints. - QSimplexConstraint *itemC = new QSimplexConstraint; - itemC->ratio = QSimplexConstraint::MoreOrEqual; - itemC->variables.insert(ad, 1.0); - itemC->constant = qMin(boundedExpSize, ad->sizeAtMaximum); - itemConstraints << itemC; - - itemC = new QSimplexConstraint; - itemC->ratio = QSimplexConstraint::LessOrEqual; - itemC->variables.insert(ad, 1.0); - itemC->constant = qMax(boundedExpSize, ad->sizeAtMaximum); - itemConstraints << itemC; - - // Create objective to avoid the anchors from moving away from - // the preferred size more than the needed amount. (ensure 3.b) - // The objective function is the distance between sizeAtPreferred - // and sizeAtExpanding, it will be minimized. - if (ad->sizeAtExpanding < ad->sizeAtMaximum) { - // Try to shrink this variable towards its sizeAtPreferred value - objective->variables.insert(ad, 1.0); - } else { - // Try to grow this variable towards its sizeAtPreferred value - objective->variables.insert(ad, -1.0); - } - } - } - - // Solve - if (hasExpanding == false) { - // If no anchors are expanding, we don't need to run the simplex - // Set all variables to their preferred size - for (int i = 0; i < variables.size(); ++i) { - variables[i]->sizeAtExpanding = variables[i]->sizeAtPreferred; - } - } else { - // Run simplex - QSimplex simplex; - - // Satisfy expanding (3.a) - bool feasible = simplex.setConstraints(constraints + itemConstraints); - Q_ASSERT(feasible); - - // Reduce damage (3.b) - simplex.setObjective(objective); - simplex.solveMin(); - - // Collect results - for (int i = 0; i < variables.size(); ++i) { - variables[i]->sizeAtExpanding = variables[i]->result; - } - } - - delete objective; - qDeleteAll(itemConstraints); -} - -/*! - \internal Returns true if there are no arrangement that satisfies all constraints. Otherwise returns false. diff --git a/src/gui/graphicsview/qgraphicsanchorlayout_p.h b/src/gui/graphicsview/qgraphicsanchorlayout_p.h index 7dd0d65..3ef37f9 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout_p.h +++ b/src/gui/graphicsview/qgraphicsanchorlayout_p.h @@ -78,66 +78,30 @@ QT_BEGIN_NAMESPACE Represents a vertex (anchorage point) in the internal graph */ struct AnchorVertex { + enum Type { + Normal = 0, + Pair + }; + AnchorVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge) - : m_item(item), m_edge(edge) {} + : m_item(item), m_edge(edge), m_type(Normal) {} AnchorVertex() - : m_item(0), m_edge(Qt::AnchorPoint(0)) {} + : m_item(0), m_edge(Qt::AnchorPoint(0)), m_type(Normal) {} #ifdef QT_DEBUG inline QString toString() const; #endif + QGraphicsLayoutItem *m_item; Qt::AnchorPoint m_edge; + uint m_type : 1; // Current distance from this vertex to the layout edge (Left or Top) // Value is calculated from the current anchors sizes. qreal distance; }; -#ifdef QT_DEBUG -inline QString AnchorVertex::toString() const -{ - if (!this || !m_item) { - return QLatin1String("NULL"); - } - QString edge; - switch (m_edge) { - case Qt::AnchorLeft: - edge = QLatin1String("Left"); - break; - case Qt::AnchorHorizontalCenter: - edge = QLatin1String("HorizontalCenter"); - break; - case Qt::AnchorRight: - edge = QLatin1String("Right"); - break; - case Qt::AnchorTop: - edge = QLatin1String("Top"); - break; - case Qt::AnchorVerticalCenter: - edge = QLatin1String("VerticalCenter"); - break; - case Qt::AnchorBottom: - edge = QLatin1String("Bottom"); - break; - default: - edge = QLatin1String("None"); - break; - } - QString itemName; - if (m_item->isLayout()) { - itemName = QLatin1String("layout"); - } else { - if (QGraphicsItem *item = m_item->graphicsItem()) { - itemName = item->data(0).toString(); - } - } - edge.insert(0, QLatin1String("%1_")); - return edge.arg(itemName); -} -#endif - /*! \internal @@ -150,14 +114,21 @@ struct AnchorData : public QSimplexVariable { Parallel }; + enum Dependency { + Independent = 0, + Master, + Slave + }; + AnchorData() : QSimplexVariable(), item(0), from(0), to(0), - minSize(0), prefSize(0), expSize(0), maxSize(0), + minSize(0), prefSize(0), maxSize(0), sizeAtMinimum(0), sizeAtPreferred(0), - sizeAtExpanding(0), sizeAtMaximum(0), + sizeAtMaximum(0), graphicsAnchor(0), skipInPreferred(0), type(Normal), hasSize(true), isLayoutAnchor(false), - isCenterAnchor(false), orientation(0) {} + isCenterAnchor(false), orientation(0), + dependency(Independent) {} virtual void updateChildrenSizes() {} virtual bool refreshSizeHints(const QLayoutStyleInfo *styleInfo); @@ -194,7 +165,6 @@ struct AnchorData : public QSimplexVariable { // size. qreal minSize; qreal prefSize; - qreal expSize; qreal maxSize; // These attributes define which sizes should that anchor be in when the @@ -202,7 +172,6 @@ struct AnchorData : public QSimplexVariable { // calculated by the Simplex solver based on the current layout setup. qreal sizeAtMinimum; qreal sizeAtPreferred; - qreal sizeAtExpanding; qreal sizeAtMaximum; QGraphicsAnchor *graphicsAnchor; @@ -212,6 +181,7 @@ struct AnchorData : public QSimplexVariable { uint isLayoutAnchor : 1; // if this anchor is an internal layout anchor uint isCenterAnchor : 1; uint orientation : 1; + uint dependency : 2; // either Independent, Master or Slave }; #ifdef QT_DEBUG @@ -250,10 +220,11 @@ struct ParallelAnchorData : public AnchorData type = AnchorData::Parallel; orientation = first->orientation; - // ### Those asserts force that both child anchors have the same direction, - // but can't we simplify a pair of anchors in opposite directions? - Q_ASSERT(first->from == second->from); - Q_ASSERT(first->to == second->to); + // This assert whether the child anchors share their vertices + Q_ASSERT(((first->from == second->from) && (first->to == second->to)) || + ((first->from == second->to) && (first->to == second->from))); + + // We arbitrarily choose the direction of the first child as "our" direction from = first->from; to = first->to; #ifdef QT_DEBUG @@ -268,8 +239,73 @@ struct ParallelAnchorData : public AnchorData AnchorData* firstEdge; AnchorData* secondEdge; + + QList<QSimplexConstraint *> m_firstConstraints; + QList<QSimplexConstraint *> m_secondConstraints; }; +struct AnchorVertexPair : public AnchorVertex { + AnchorVertexPair(AnchorVertex *v1, AnchorVertex *v2, AnchorData *data) + : AnchorVertex(), m_first(v1), m_second(v2), m_removedAnchor(data) { + m_type = AnchorVertex::Pair; + } + + AnchorVertex *m_first; + AnchorVertex *m_second; + + AnchorData *m_removedAnchor; + QList<AnchorData *> m_firstAnchors; + QList<AnchorData *> m_secondAnchors; +}; + +#ifdef QT_DEBUG +inline QString AnchorVertex::toString() const +{ + if (!this) { + return QLatin1String("NULL"); + } else if (m_type == Pair) { + const AnchorVertexPair *vp = static_cast<const AnchorVertexPair *>(this); + return QString::fromAscii("(%1, %2)").arg(vp->m_first->toString()).arg(vp->m_second->toString()); + } else if (!m_item) { + return QString::fromAscii("NULL_%1").arg(int(this)); + } + QString edge; + switch (m_edge) { + case Qt::AnchorLeft: + edge = QLatin1String("Left"); + break; + case Qt::AnchorHorizontalCenter: + edge = QLatin1String("HorizontalCenter"); + break; + case Qt::AnchorRight: + edge = QLatin1String("Right"); + break; + case Qt::AnchorTop: + edge = QLatin1String("Top"); + break; + case Qt::AnchorVerticalCenter: + edge = QLatin1String("VerticalCenter"); + break; + case Qt::AnchorBottom: + edge = QLatin1String("Bottom"); + break; + default: + edge = QLatin1String("None"); + break; + } + QString itemName; + if (m_item->isLayout()) { + itemName = QLatin1String("layout"); + } else { + if (QGraphicsItem *item = m_item->graphicsItem()) { + itemName = item->data(0).toString(); + } + } + edge.insert(0, QLatin1String("%1_")); + return edge.arg(itemName); +} +#endif + /*! \internal @@ -337,8 +373,7 @@ public: // Interval represents which interpolation interval are we operating in. enum Interval { MinToPreferred = 0, - PreferredToExpanding, - ExpandingToMax + PreferredToMax }; // Several structures internal to the layout are duplicated to handle @@ -427,20 +462,33 @@ public: QLayoutStyleInfo &styleInfo() const; - // Activation methods - bool simplifyGraph(Orientation orientation); - bool simplifyGraphIteration(Orientation orientation, bool *feasible); - void restoreSimplifiedGraph(Orientation orientation); + AnchorData *addAnchorMaybeParallel(AnchorData *newAnchor, bool *feasible); + // Activation void calculateGraphs(); void calculateGraphs(Orientation orientation); + // Simplification + bool simplifyGraph(Orientation orientation); + bool simplifyVertices(Orientation orientation); + bool simplifyGraphIteration(Orientation orientation, bool *feasible); + + bool replaceVertex(Orientation orientation, AnchorVertex *oldV, + AnchorVertex *newV, const QList<AnchorData *> &edges); + + + void restoreSimplifiedGraph(Orientation orientation); + void restoreSimplifiedAnchor(AnchorData *edge); + void restoreSimplifiedConstraints(ParallelAnchorData *parallel); + void restoreVertices(Orientation orientation); + bool calculateTrunk(Orientation orientation, const GraphPath &trunkPath, const QList<QSimplexConstraint *> &constraints, const QList<AnchorData *> &variables); bool calculateNonTrunk(const QList<QSimplexConstraint *> &constraints, const QList<AnchorData *> &variables); + // Support functions for calculateGraph() bool refreshAllSizeHints(Orientation orientation); void findPaths(Orientation orientation); void constraintsFromPaths(Orientation orientation); @@ -460,6 +508,17 @@ public: return internalVertex(qMakePair(const_cast<QGraphicsLayoutItem *>(item), edge)); } + inline void changeLayoutVertex(Orientation orientation, AnchorVertex *oldV, AnchorVertex *newV) + { + if (layoutFirstVertex[orientation] == oldV) + layoutFirstVertex[orientation] = newV; + else if (layoutCentralVertex[orientation] == oldV) + layoutCentralVertex[orientation] = newV; + else if (layoutLastVertex[orientation] == oldV) + layoutLastVertex[orientation] = newV; + } + + AnchorVertex *addInternalVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge); void removeInternalVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge); @@ -468,19 +527,15 @@ public: void calculateVertexPositions(Orientation orientation); void setupEdgesInterpolation(Orientation orientation); - void interpolateEdge(AnchorVertex *base, AnchorData *edge, Orientation orientation); - void interpolateSequentialEdges(AnchorVertex *base, SequentialAnchorData *edge, - Orientation orientation); - void interpolateParallelEdges(AnchorVertex *base, ParallelAnchorData *edge, - Orientation orientation); + void interpolateEdge(AnchorVertex *base, AnchorData *edge); + void interpolateSequentialEdges(SequentialAnchorData *edge); + void interpolateParallelEdges(ParallelAnchorData *edge); // Linear Programming solver methods bool solveMinMax(const QList<QSimplexConstraint *> &constraints, GraphPath path, qreal *min, qreal *max); bool solvePreferred(const QList<QSimplexConstraint *> &constraints, const QList<AnchorData *> &variables); - void solveExpanding(const QList<QSimplexConstraint *> &constraints, - const QList<AnchorData *> &variables); bool hasConflicts() const; #ifdef QT_DEBUG @@ -491,7 +546,6 @@ public: qreal spacings[NOrientations]; // Size hints from simplex engine qreal sizeHints[2][3]; - qreal sizeAtExpanding[2]; // Items QVector<QGraphicsLayoutItem *> items; @@ -504,6 +558,14 @@ public: // Internal graph of anchorage points and anchors, for both orientations Graph<AnchorVertex, AnchorData> graph[2]; + AnchorVertex *layoutFirstVertex[2]; + AnchorVertex *layoutCentralVertex[2]; + AnchorVertex *layoutLastVertex[2]; + + // Combined anchors in order of creation + QList<AnchorVertexPair *> simplifiedVertices[2]; + QList<AnchorData *> anchorsFromSimplifiedVertices[2]; + // Graph paths and constraints, for both orientations QMultiHash<AnchorVertex *, GraphPath> graphPaths[2]; QList<QSimplexConstraint *> constraints[2]; diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index b6172ab..70457b5 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -386,6 +386,12 @@ introduced in Qt 4.6. \omitvalue ItemIsFocusScope Internal only (for now). + + \value ItemSendsScenePositionChanges The item enables itemChange() + notifications for ItemScenePositionHasChanged. For performance reasons, + these notifications are disabled by default. You must enable this flag + to receive notifications for scene position changes. This flag was + introduced in Qt 4.6. */ /*! @@ -562,6 +568,14 @@ \value ItemOpacityHasChanged The item's opacity has changed. The value argument is the new opacity (i.e., a double). Do not call setOpacity() as this notification is delivered. The return value is ignored. + + \value ItemScenePositionHasChanged The item's scene position has changed. + This notification is sent if the ItemSendsScenePositionChanges flag is + enabled, and after the item's scene position has changed (i.e., the + position or transformation of the item itself or the position or + transformation of any ancestor has changed). The value argument is the + new scene position (the same as scenePos()), and QGraphicsItem ignores + the return value for this notification (i.e., a read-only notification). */ /*! @@ -990,6 +1004,10 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent) if (scene) { // Deliver the change to the index scene->d_func()->index->itemChange(q, QGraphicsItem::ItemParentChange, newParentVariant); + + // Disable scene pos notifications for old ancestors + if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges)) + scene->d_func()->setScenePosItemEnabled(q, false); } if (subFocusItem && parent) { @@ -1084,10 +1102,15 @@ void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent) parent->d_ptr->addChild(q); parent->itemChange(QGraphicsItem::ItemChildAddedChange, thisPointerVariant); - if (!implicitUpdate && scene) { - scene->d_func()->markDirty(q_ptr, QRect(), - /*invalidateChildren=*/false, - /*maybeDirtyClipPath=*/true); + if (scene) { + if (!implicitUpdate) + scene->d_func()->markDirty(q_ptr, QRect(), + /*invalidateChildren=*/false, + /*maybeDirtyClipPath=*/true); + + // Re-enable scene pos notifications for new ancestors + if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges)) + scene->d_func()->setScenePosItemEnabled(q, true); } // Inherit ancestor flags from the new parent. @@ -1336,7 +1359,9 @@ QGraphicsItem::~QGraphicsItem() d_ptr->setParentItemHelper(0); } +#ifndef QT_NO_GRAPHICSEFFECT delete d_ptr->graphicsEffect; +#endif //QT_NO_GRAPHICSEFFECT if (d_ptr->transformData) { for(int i = 0; i < d_ptr->transformData->graphicsTransforms.size(); ++i) { QGraphicsTransform *t = d_ptr->transformData->graphicsTransforms.at(i); @@ -1746,6 +1771,12 @@ void QGraphicsItem::setFlags(GraphicsItemFlags flags) } if (d_ptr->scene) { + if ((flags & ItemSendsScenePositionChanges) != (oldFlags & ItemSendsScenePositionChanges)) { + if (flags & ItemSendsScenePositionChanges) + d_ptr->scene->d_func()->registerScenePosItem(this); + else + d_ptr->scene->d_func()->unregisterScenePosItem(this); + } d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true, /*maybeDirtyClipPath*/true); @@ -2506,7 +2537,9 @@ void QGraphicsItem::setOpacity(qreal opacity) // Update. if (d_ptr->scene) { +#ifndef QT_NO_GRAPHICSEFFECT d_ptr->invalidateGraphicsEffectsRecursively(); +#endif //QT_NO_GRAPHICSEFFECT d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true, /*maybeDirtyClipPath=*/false, @@ -2523,6 +2556,7 @@ void QGraphicsItem::setOpacity(qreal opacity) \since 4.6 */ +#ifndef QT_NO_GRAPHICSEFFECT QGraphicsEffect *QGraphicsItem::graphicsEffect() const { return d_ptr->graphicsEffect; @@ -2569,6 +2603,7 @@ void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect) prepareGeometryChange(); } +#endif //QT_NO_GRAPHICSEFFECT /*! \internal @@ -2582,6 +2617,7 @@ 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(); if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) @@ -2598,6 +2634,10 @@ QRectF QGraphicsItemPrivate::effectiveBoundingRect() const } return brect; +#else //QT_NO_GRAPHICSEFFECT + return q_ptr->boundingRect(); +#endif //QT_NO_GRAPHICSEFFECT + } /*! @@ -2951,7 +2991,7 @@ bool QGraphicsItem::hasFocus() const { if (d_ptr->focusProxy) return d_ptr->focusProxy->hasFocus(); - return (d_ptr->scene && d_ptr->scene->focusItem() == this); + return isActive() && (d_ptr->scene && d_ptr->scene->focusItem() == this); } /*! @@ -3412,6 +3452,7 @@ void QGraphicsItem::setPos(const QPointF &pos) // Send post-notification. itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant); + d_ptr->sendScenePosChange(); } /*! @@ -4022,6 +4063,7 @@ void QGraphicsItem::setTransform(const QTransform &matrix, bool combine) // Send post-notification. itemChange(ItemTransformHasChanged, newTransformVariant); + d_ptr->sendScenePosChange(); } /*! @@ -4246,6 +4288,24 @@ void QGraphicsItemPrivate::ensureSequentialSiblingIndex() } /*! + \internal +*/ +inline void QGraphicsItemPrivate::sendScenePosChange() +{ + Q_Q(QGraphicsItem); + if (scene) { + if (flags & QGraphicsItem::ItemSendsScenePositionChanges) + q->itemChange(QGraphicsItem::ItemScenePositionHasChanged, q->scenePos()); + if (scenePosDescendants) { + foreach (QGraphicsItem *item, scene->d_func()->scenePosItems) { + if (q->isAncestorOf(item)) + item->itemChange(QGraphicsItem::ItemScenePositionHasChanged, item->scenePos()); + } + } + } +} + +/*! \since 4.6 Stacks this item before \a sibling, which must be a sibling item (i.e., the @@ -4296,6 +4356,12 @@ void QGraphicsItem::stackBefore(const QGraphicsItem *sibling) ++index; } d_ptr->siblingIndex = siblingIndex; + for (int i = 0; i < siblings->size(); ++i) { + int &index = siblings->at(i)->d_ptr->siblingIndex; + if (i != siblingIndex && index >= siblingIndex && index <= myIndex) + siblings->at(i)->d_ptr->siblingOrderChange(); + } + d_ptr->siblingOrderChange(); } } @@ -4977,6 +5043,7 @@ int QGraphicsItemPrivate::depth() const /*! \internal */ +#ifndef QT_NO_GRAPHICSEFFECT void QGraphicsItemPrivate::invalidateGraphicsEffectsRecursively() { QGraphicsItemPrivate *itemPrivate = this; @@ -4989,6 +5056,7 @@ void QGraphicsItemPrivate::invalidateGraphicsEffectsRecursively() } } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : 0)); } +#endif //QT_NO_GRAPHICSEFFECT /*! \internal @@ -5293,6 +5361,16 @@ void QGraphicsItemPrivate::subFocusItemChange() /*! \internal + Subclasses can reimplement this function to be notified when its + siblingIndex order is changed. +*/ +void QGraphicsItemPrivate::siblingOrderChange() +{ +} + +/*! + \internal + Tells us if it is a proxy widget */ bool QGraphicsItemPrivate::isProxyWidget() const @@ -5324,7 +5402,9 @@ void QGraphicsItem::update(const QRectF &rect) return; // Make sure we notify effects about invalidated source. +#ifndef QT_NO_GRAPHICSEFFECT d_ptr->invalidateGraphicsEffectsRecursively(); +#endif //QT_NO_GRAPHICSEFFECT if (CacheMode(d_ptr->cacheMode) != NoCache) { // Invalidate cache. @@ -10679,6 +10759,7 @@ int QGraphicsItemGroup::type() const return Type; } +#ifndef QT_NO_GRAPHICSEFFECT QRectF QGraphicsItemEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const { const bool deviceCoordinates = (system == Qt::DeviceCoordinates); @@ -10818,6 +10899,7 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP return pixmap; } +#endif //QT_NO_GRAPHICSEFFECT #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, QGraphicsItem *item) @@ -10941,6 +11023,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemChange change) case QGraphicsItem::ItemOpacityHasChanged: str = "ItemOpacityHasChanged"; break; + case QGraphicsItem::ItemScenePositionHasChanged: + str = "ItemScenePositionHasChanged"; + break; } debug << str; return debug; @@ -10998,6 +11083,9 @@ QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag) case QGraphicsItem::ItemIsFocusScope: str = "ItemIsFocusScope"; break; + case QGraphicsItem::ItemSendsScenePositionChanges: + str = "ItemSendsScenePositionChanges"; + break; } debug << str; return debug; diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index f091e34..8bbe9f1 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -105,7 +105,8 @@ public: ItemAcceptsInputMethod = 0x1000, ItemNegativeZStacksBehindParent = 0x2000, ItemIsPanel = 0x4000, - ItemIsFocusScope = 0x8000 // internal + ItemIsFocusScope = 0x8000, // internal + ItemSendsScenePositionChanges = 0x10000 // NB! Don't forget to increase the d_ptr->flags bit field by 1 when adding a new flag. }; Q_DECLARE_FLAGS(GraphicsItemFlags, GraphicsItemFlag) @@ -137,7 +138,8 @@ public: ItemZValueChange, ItemZValueHasChanged, ItemOpacityChange, - ItemOpacityHasChanged + ItemOpacityHasChanged, + ItemScenePositionHasChanged }; enum CacheMode { @@ -225,9 +227,11 @@ public: qreal effectiveOpacity() const; void setOpacity(qreal opacity); +#ifndef QT_NO_GRAPHICSEFFECT // Effect QGraphicsEffect *graphicsEffect() const; void setGraphicsEffect(QGraphicsEffect *effect); +#endif //QT_NO_GRAPHICSEFFECT Qt::MouseButtons acceptedMouseButtons() const; void setAcceptedMouseButtons(Qt::MouseButtons buttons); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 51d2ffd..afc2198 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -179,6 +179,7 @@ public: holesInSiblingIndex(0), sequentialOrdering(1), updateDueToGraphicsEffect(0), + scenePosDescendants(0), globalStackingOrder(-1), q_ptr(0) { @@ -223,7 +224,9 @@ public: bool discardUpdateRequest(bool ignoreClipping = false, bool ignoreVisibleBit = false, bool ignoreDirtyBit = false, bool ignoreOpacity = false) const; int depth() const; +#ifndef QT_NO_GRAPHICSEFFECT void invalidateGraphicsEffectsRecursively(); +#endif //QT_NO_GRAPHICSEFFECT void invalidateDepthRecursively(); void resolveDepth(); void addChild(QGraphicsItem *child); @@ -429,6 +432,8 @@ public: inline void ensureSortedChildren(); static inline bool insertionOrder(QGraphicsItem *a, QGraphicsItem *b); void ensureSequentialSiblingIndex(); + inline void sendScenePosChange(); + virtual void siblingOrderChange(); QPainterPath cachedClipPath; QRectF childrenBoundingRect; @@ -483,7 +488,7 @@ public: // Packed 32 bits quint32 fullUpdatePending : 1; - quint32 flags : 16; + quint32 flags : 17; quint32 dirtyChildrenBoundingRect : 1; quint32 paintedViewBoundingRectsNeedRepaint : 1; quint32 dirtySceneTransform : 1; @@ -498,14 +503,15 @@ public: quint32 sceneTransformTranslateOnly : 1; quint32 notifyBoundingRectChanged : 1; quint32 notifyInvalidated : 1; - quint32 mouseSetsFocus : 1; // New 32 bits + quint32 mouseSetsFocus : 1; quint32 explicitActivate : 1; quint32 wantsActive : 1; quint32 holesInSiblingIndex : 1; quint32 sequentialOrdering : 1; quint32 updateDueToGraphicsEffect : 1; + quint32 scenePosDescendants : 1; // Optional stacking order int globalStackingOrder; @@ -577,6 +583,7 @@ struct QGraphicsItemPaintInfo quint32 drawItem : 1; }; +#ifndef QT_NO_GRAPHICSEFFECT class QGraphicsItemEffectSourcePrivate : public QGraphicsEffectSourcePrivate { public: @@ -632,7 +639,7 @@ public: QGraphicsItemPaintInfo *info; QTransform lastEffectTransform; }; - +#endif //QT_NO_GRAPHICSEFFECT /*! Returns true if \a item1 is on top of \a item2. diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 8431fe9..01f0e97 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -294,6 +294,7 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() needSortTopLevelItems(true), holesInTopLevelSiblingIndex(false), topLevelSequentialOrdering(true), + scenePosDescendantsUpdatePending(false), stickyFocus(false), hasFocus(false), focusItem(0), @@ -488,6 +489,55 @@ void QGraphicsScenePrivate::_q_processDirtyItems() /*! \internal +*/ +void QGraphicsScenePrivate::setScenePosItemEnabled(QGraphicsItem *item, bool enabled) +{ + QGraphicsItem *p = item->d_ptr->parent; + while (p) { + p->d_ptr->scenePosDescendants = enabled; + p = p->d_ptr->parent; + } + if (!enabled && !scenePosDescendantsUpdatePending) { + scenePosDescendantsUpdatePending = true; + QMetaObject::invokeMethod(q_func(), "_q_updateScenePosDescendants", Qt::QueuedConnection); + } +} + +/*! + \internal +*/ +void QGraphicsScenePrivate::registerScenePosItem(QGraphicsItem *item) +{ + scenePosItems.insert(item); + setScenePosItemEnabled(item, true); +} + +/*! + \internal +*/ +void QGraphicsScenePrivate::unregisterScenePosItem(QGraphicsItem *item) +{ + scenePosItems.remove(item); + setScenePosItemEnabled(item, false); +} + +/*! + \internal +*/ +void QGraphicsScenePrivate::_q_updateScenePosDescendants() +{ + foreach (QGraphicsItem *item, scenePosItems) { + QGraphicsItem *p = item->d_ptr->parent; + while (p) { + p->d_ptr->scenePosDescendants = 1; + p = p->d_ptr->parent; + } + } + scenePosDescendantsUpdatePending = false; +} + +/*! + \internal Schedules an item for removal. This function leaves some stale indexes around in the BSP tree if called from the item's destructor; these will @@ -523,6 +573,9 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item) widget->d_func()->fixFocusChainBeforeReparenting(0, 0); } + if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges) + unregisterScenePosItem(item); + item->d_func()->scene = 0; //We need to remove all children first because they might use their parent @@ -2293,8 +2346,9 @@ void QGraphicsScene::clear() // NB! We have to clear the index before deleting items; otherwise the // index might try to access dangling item pointers. d->index->clear(); - const QList<QGraphicsItem *> items = d->topLevelItems; - qDeleteAll(items); + // NB! QGraphicsScenePrivate::unregisterTopLevelItem() removes items + while (!d->topLevelItems.isEmpty()) + delete d->topLevelItems.first(); Q_ASSERT(d->topLevelItems.isEmpty()); d->lastItemCount = 0; d->allItemsIgnoreHoverEvents = true; @@ -2540,6 +2594,9 @@ void QGraphicsScene::addItem(QGraphicsItem *item) } } + if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges) + d->registerScenePosItem(item); + // Ensure that newly added items that have subfocus set, gain // focus automatically if there isn't a focus item already. if (!d->focusItem && item != d->lastFocusItem && item->focusItem() == item) @@ -2826,18 +2883,20 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) } /*! - Returns the scene's current focus item, or 0 if no item currently has - focus. + When the scene is active, this functions returns the scene's current focus + item, or 0 if no item currently has focus. When the scene is inactive, this + functions returns the item that will gain input focus when the scene becomes + active. The focus item receives keyboard input when the scene receives a key event. - \sa setFocusItem(), QGraphicsItem::hasFocus() + \sa setFocusItem(), QGraphicsItem::hasFocus(), isActive() */ QGraphicsItem *QGraphicsScene::focusItem() const { Q_D(const QGraphicsScene); - return d->focusItem; + return isActive() ? d->focusItem : d->lastFocusItem; } /*! @@ -4577,6 +4636,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * if (itemHasChildren && itemClipsChildrenToShape) ENSURE_TRANSFORM_PTR; +#ifndef QT_NO_GRAPHICSEFFECT if (item->d_ptr->graphicsEffect && item->d_ptr->graphicsEffect->isEnabled()) { ENSURE_TRANSFORM_PTR; QGraphicsItemPaintInfo info(viewTransform, transformPtr, effectTransform, exposedRegion, widget, &styleOptionTmp, @@ -4599,7 +4659,9 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter * item->d_ptr->graphicsEffect->draw(painter, source); painter->setWorldTransform(restoreTransform); sourced->info = 0; - } else { + } else +#endif //QT_NO_GRAPHICSEFFECT + { draw(item, painter, viewTransform, transformPtr, exposedRegion, widget, opacity, effectTransform, wasDirtyParentSceneTransform, drawItem); } @@ -4768,10 +4830,12 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b QGraphicsItem *p = item->d_ptr->parent; while (p) { p->d_ptr->dirtyChildren = 1; +#ifndef QT_NO_GRAPHICSEFFECT if (p->d_ptr->graphicsEffect && p->d_ptr->graphicsEffect->isEnabled()) { p->d_ptr->dirty = 1; p->d_ptr->fullUpdatePending = 1; } +#endif //QT_NO_GRAPHICSEFFECT p = p->d_ptr->parent; } } diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h index d6d48d7..a47574e 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -299,6 +299,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_emitUpdated()) Q_PRIVATE_SLOT(d_func(), void _q_polishItems()) Q_PRIVATE_SLOT(d_func(), void _q_processDirtyItems()) + Q_PRIVATE_SLOT(d_func(), void _q_updateScenePosDescendants()) friend class QGraphicsItem; friend class QGraphicsItemPrivate; friend class QGraphicsView; diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index f8db084..fdec466 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -122,6 +122,13 @@ public: void _q_processDirtyItems(); + QSet<QGraphicsItem *> scenePosItems; + bool scenePosDescendantsUpdatePending; + void setScenePosItemEnabled(QGraphicsItem *item, bool enabled); + void registerScenePosItem(QGraphicsItem *item); + void unregisterScenePosItem(QGraphicsItem *item); + void _q_updateScenePosDescendants(); + void removeItemHelper(QGraphicsItem *item); QBrush backgroundBrush; @@ -234,6 +241,7 @@ public: item->d_ptr->fullUpdatePending = 0; item->d_ptr->ignoreVisible = 0; item->d_ptr->ignoreOpacity = 0; +#ifndef QT_NO_GRAPHICSEFFECT QGraphicsEffect::ChangeFlags flags; if (item->d_ptr->notifyBoundingRectChanged) { flags |= QGraphicsEffect::SourceBoundingRectChanged; @@ -243,12 +251,15 @@ public: flags |= QGraphicsEffect::SourceInvalidated; item->d_ptr->notifyInvalidated = 0; } +#endif //QT_NO_GRAPHICSEFFECT if (recursive) { for (int i = 0; i < item->d_ptr->children.size(); ++i) resetDirtyItem(item->d_ptr->children.at(i), recursive); } +#ifndef QT_NO_GRAPHICSEFFECT if (flags && item->d_ptr->graphicsEffect) item->d_ptr->graphicsEffect->sourceChanged(flags); +#endif //QT_NO_GRAPHICSEFFECT } inline void ensureSortedTopLevelItems() diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 7ac1a8f..26efe58 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -1512,6 +1512,11 @@ void QGraphicsView::setScene(QGraphicsScene *scene) this, SLOT(updateSceneRect(QRectF))); d->scene->d_func()->removeView(this); d->connectedToScene = false; + + if (isActiveWindow() && isVisible()) { + QEvent windowDeactivate(QEvent::WindowDeactivate); + QApplication::sendEvent(d->scene, &windowDeactivate); + } } // Assign the new scene and update the contents (scrollbars, etc.)). @@ -1533,6 +1538,11 @@ void QGraphicsView::setScene(QGraphicsScene *scene) // enable touch events if any items is interested in them if (!d->scene->d_func()->allItemsIgnoreTouchEvents) d->viewport->setAttribute(Qt::WA_AcceptTouchEvents); + + if (isActiveWindow() && isVisible()) { + QEvent windowActivate(QEvent::WindowActivate); + QApplication::sendEvent(d->scene, &windowActivate); + } } else { d->recalculateContentSize(); } @@ -2638,6 +2648,19 @@ bool QGraphicsView::viewportEvent(QEvent *event) d->scene->d_func()->removePopup(d->scene->d_func()->popupWidgets.first()); QApplication::sendEvent(d->scene, event); break; + case QEvent::Show: + if (d->scene && isActiveWindow()) { + QEvent windowActivate(QEvent::WindowActivate); + QApplication::sendEvent(d->scene, &windowActivate); + } + break; + case QEvent::Hide: + // spontaneous event will generate a WindowDeactivate. + if (!event->spontaneous() && d->scene && isActiveWindow()) { + QEvent windowDeactivate(QEvent::WindowDeactivate); + QApplication::sendEvent(d->scene, &windowDeactivate); + } + break; case QEvent::Leave: // ### This is a temporary fix for until we get proper mouse grab // events. activeMouseGrabberItem should be set to 0 if we lose the @@ -3252,10 +3275,13 @@ void QGraphicsView::paintEvent(QPaintEvent *event) // Determine the exposed region d->exposedRegion = event->region(); + if (d->exposedRegion.isEmpty()) + d->exposedRegion = viewport()->rect(); QRectF exposedSceneRect = mapToScene(d->exposedRegion.boundingRect()).boundingRect(); // Set up the painter QPainter painter(viewport()); + painter.setClipRect(event->rect(), Qt::IntersectClip); #ifndef QT_NO_RUBBERBAND if (d->rubberBanding && !d->rubberBandRect.isEmpty()) painter.save(); diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index d70a281..d9c65bb 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -318,6 +318,12 @@ void QGraphicsWidget::resize(const QSizeF &size) */ /*! + \property QGraphicsWidget::sizePolicy + \brief the size policy for the widget + \sa sizePolicy(), setSizePolicy(), QWidget::sizePolicy() +*/ + +/*! \property QGraphicsWidget::geometry \brief the geometry of the widget @@ -410,6 +416,27 @@ void QGraphicsWidget::setGeometry(const QRectF &rect) */ /*! + \property QGraphicsWidget::minimumSize + \brief the minimum size of the widget + + \sa setMinimumSize(), minimumSize(), preferredSize, maximumSize +*/ + +/*! + \property QGraphicsWidget::preferredSize + \brief the preferred size of the widget + + \sa setPreferredSize(), preferredSize(), minimumSize, maximumSize +*/ + +/*! + \property QGraphicsWidget::maximumSize + \brief the maximum size of the widget + + \sa setMaximumSize(), maximumSize(), minimumSize, preferredSize +*/ + +/*! Sets the widget's contents margins to \a left, \a top, \a right and \a bottom. diff --git a/src/gui/graphicsview/qgraphicswidget.h b/src/gui/graphicsview/qgraphicswidget.h index 9c71140..05d3a49 100644 --- a/src/gui/graphicsview/qgraphicswidget.h +++ b/src/gui/graphicsview/qgraphicswidget.h @@ -74,6 +74,10 @@ class Q_GUI_EXPORT QGraphicsWidget : public QGraphicsObject, public QGraphicsLay Q_PROPERTY(QFont font READ font WRITE setFont) Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection RESET unsetLayoutDirection) Q_PROPERTY(QSizeF size READ size WRITE resize) + Q_PROPERTY(QSizeF minimumSize READ minimumSize WRITE setMinimumSize) + Q_PROPERTY(QSizeF preferredSize READ preferredSize WRITE setPreferredSize) + Q_PROPERTY(QSizeF maximumSize READ maximumSize WRITE setMaximumSize) + Q_PROPERTY(QSizePolicy sizePolicy READ sizePolicy WRITE setSizePolicy) Q_PROPERTY(Qt::FocusPolicy focusPolicy READ focusPolicy WRITE setFocusPolicy) Q_PROPERTY(Qt::WindowFlags windowFlags READ windowFlags WRITE setWindowFlags) Q_PROPERTY(QString windowTitle READ windowTitle WRITE setWindowTitle) diff --git a/src/gui/graphicsview/qsimplex_p.cpp b/src/gui/graphicsview/qsimplex_p.cpp index 5ad329e..1b3eaf9 100644 --- a/src/gui/graphicsview/qsimplex_p.cpp +++ b/src/gui/graphicsview/qsimplex_p.cpp @@ -288,7 +288,7 @@ bool QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints) // original problem. // Otherwise, we clean up our structures and report there is // no feasible solution. - if (valueAt(0, columns - 1) != 0.0) { + if ((valueAt(0, columns - 1) != 0.0) && (qAbs(valueAt(0, columns - 1)) > 0.00001)) { qWarning() << "QSimplex: No feasible solution!"; clearDataStructures(); return false; diff --git a/src/gui/graphicsview/qsimplex_p.h b/src/gui/graphicsview/qsimplex_p.h index 084ad7f..a5816d1 100644 --- a/src/gui/graphicsview/qsimplex_p.h +++ b/src/gui/graphicsview/qsimplex_p.h @@ -107,7 +107,7 @@ struct QSimplexConstraint Q_ASSERT(constant > 0 || qFuzzyCompare(1, 1 + constant)); - if ((leftHandSide == constant) || qFuzzyCompare(1000 + leftHandSide, 1000 + constant)) + if ((leftHandSide == constant) || qAbs(leftHandSide - constant) < 0.00000001) return true; switch (ratio) { diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index c452b9a..dfeea76 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -639,13 +639,13 @@ void QPixmap::resize_helper(const QSize &s) QPixmap pm(QSize(w, h), data ? data->type : QPixmapData::PixmapType); bool uninit = false; #if defined(Q_WS_X11) - QX11PixmapData *x11Data = data->classId() == QPixmapData::X11Class ? static_cast<QX11PixmapData*>(data.data()) : 0; + QX11PixmapData *x11Data = data && data->classId() == QPixmapData::X11Class ? static_cast<QX11PixmapData*>(data.data()) : 0; if (x11Data) { pm.x11SetScreen(x11Data->xinfo.screen()); uninit = x11Data->flags & QX11PixmapData::Uninitialized; } #elif defined(Q_WS_MAC) - QMacPixmapData *macData = data->classId() == QPixmapData::MacClass ? static_cast<QMacPixmapData*>(data.data()) : 0; + QMacPixmapData *macData = data && data->classId() == QPixmapData::MacClass ? static_cast<QMacPixmapData*>(data.data()) : 0; if (macData) uninit = macData->uninit; #endif diff --git a/src/gui/itemviews/qlistview.cpp b/src/gui/itemviews/qlistview.cpp index d680af8..15db9a6 100644 --- a/src/gui/itemviews/qlistview.cpp +++ b/src/gui/itemviews/qlistview.cpp @@ -357,7 +357,7 @@ QListView::LayoutMode QListView::layoutMode() const /*! \property QListView::spacing - \brief the space between items in the layout + \brief the space around the items in the layout This property is the size of the empty space that is padded around an item in the layout. @@ -972,9 +972,9 @@ void QListView::paintEvent(QPaintEvent *e) option.rect = visualRect(*it); if (flow() == TopToBottom) - option.rect.setWidth(qMin(viewport()->size().width(), option.rect.width())); + option.rect.setWidth(qMin(viewport()->size().width() - 2 * d->spacing(), option.rect.width())); else - option.rect.setHeight(qMin(viewport()->size().height(), option.rect.height())); + option.rect.setHeight(qMin(viewport()->size().height() - 2 * d->spacing(), option.rect.height())); option.state = state; if (selections && selections->isSelected(*it)) @@ -1837,14 +1837,14 @@ void QCommonListViewBase::updateHorizontalScrollBar(const QSize &step) { horizontalScrollBar()->setSingleStep(step.width() + spacing()); horizontalScrollBar()->setPageStep(viewport()->width()); - horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width()); + horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width() - 2 * spacing()); } void QCommonListViewBase::updateVerticalScrollBar(const QSize &step) { verticalScrollBar()->setSingleStep(step.height() + spacing()); verticalScrollBar()->setPageStep(viewport()->height()); - verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height()); + verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height() - 2 * spacing()); } void QCommonListViewBase::scrollContentsBy(int dx, int dy, bool /*scrollElasticBand*/) diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index 3856293..a3cbc0d 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -2113,6 +2113,12 @@ QModelIndex QTreeView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie if (vi < 0) vi = qMax(0, d->viewIndex(current)); + if (isRightToLeft()) { + if (cursorAction == MoveRight) + cursorAction = MoveLeft; + else if (cursorAction == MoveLeft) + cursorAction = MoveRight; + } switch (cursorAction) { case MoveNext: case MoveDown: diff --git a/src/gui/itemviews/qtreeview_p.h b/src/gui/itemviews/qtreeview_p.h index aad5837..d58dea3 100644 --- a/src/gui/itemviews/qtreeview_p.h +++ b/src/gui/itemviews/qtreeview_p.h @@ -105,7 +105,7 @@ public: int top() const { return startValue().toInt(); } QRect rect() const { QRect rect = viewport->rect(); rect.moveTop(top()); return rect; } void updateCurrentValue(const QVariant &) { viewport->update(rect()); } - void updateState(State, State state) { if (state == Stopped) before = after = QPixmap(); } + void updateState(State state, State) { if (state == Stopped) before = after = QPixmap(); } } animatedOperation; void prepareAnimatedOperation(int item, QVariantAnimation::Direction d); void beginAnimatedOperation(); diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm index 84e0d50..84da56e 100644 --- a/src/gui/kernel/qapplication_mac.mm +++ b/src/gui/kernel/qapplication_mac.mm @@ -104,6 +104,7 @@ #include "qdir.h" #include "qdebug.h" #include "qtimer.h" +#include "qurl.h" #include "private/qmacinputcontext_p.h" #include "private/qpaintengine_mac_p.h" #include "private/qcursor_p.h" @@ -966,7 +967,8 @@ struct QMacAppleEventTypeSpec { AEEventID mac_id; } app_apple_events[] = { { kCoreEventClass, kAEQuitApplication }, - { kCoreEventClass, kAEOpenDocuments } + { kCoreEventClass, kAEOpenDocuments }, + { kInternetEventClass, kAEGetURL }, }; #ifndef QT_MAC_USE_COCOA @@ -1201,7 +1203,7 @@ void qt_init(QApplicationPrivate *priv, int) app_proc_ae_handlerUPP = AEEventHandlerUPP(QApplicationPrivate::globalAppleEventProcessor); for(uint i = 0; i < sizeof(app_apple_events) / sizeof(QMacAppleEventTypeSpec); ++i) AEInstallEventHandler(app_apple_events[i].mac_class, app_apple_events[i].mac_id, - app_proc_ae_handlerUPP, SRefCon(qApp), true); + app_proc_ae_handlerUPP, SRefCon(qApp), false); } if (QApplicationPrivate::app_style) { @@ -1237,6 +1239,10 @@ void qt_init(QApplicationPrivate *priv, int) [cocoaApp setMenu:[qtMenuLoader menu]]; [newDelegate setMenuLoader:qtMenuLoader]; [qtMenuLoader release]; + + NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager]; + [eventManager setEventHandler:newDelegate andSelector:@selector(getUrl:withReplyEvent:) + forEventClass:kInternetEventClass andEventID:kAEGetURL]; } #endif // Register for Carbon tablet proximity events on the event monitor target. @@ -2477,6 +2483,22 @@ OSStatus QApplicationPrivate::globalAppleEventProcessor(const AppleEvent *ae, Ap default: break; } + } else if (aeClass == kInternetEventClass) { + switch (aeID) { + case kAEGetURL: { + char urlData[1024]; + Size actualSize; + if (AEGetParamPtr(ae, keyDirectObject, typeChar, 0, urlData, + sizeof(urlData) - 1, &actualSize) == noErr) { + urlData[actualSize] = 0; + QFileOpenEvent ev(QUrl(QString::fromUtf8(urlData))); + QApplication::sendSpontaneousEvent(app, &ev); + } + break; + } + default: + break; + } } #ifdef DEBUG_EVENTS qDebug("Qt: internal: %shandled Apple event! %c%c%c%c %c%c%c%c", handled_event ? "(*)" : "", diff --git a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm index d103cbd..37dcc67 100644 --- a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm +++ b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm @@ -83,6 +83,7 @@ #include <private/qt_cocoa_helpers_mac_p.h> #include <private/qdesktopwidget_mac_p.h> #include <qevent.h> +#include <qurl.h> #include <qapplication.h> QT_BEGIN_NAMESPACE @@ -303,5 +304,15 @@ static void cleanupCocoaApplicationDelegate() [self doesNotRecognizeSelector:invocationSelector]; } +- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent +{ + Q_UNUSED(replyEvent); + + NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; + QUrl url(qt_mac_NSStringToQString(urlString)); + QFileOpenEvent qtEvent(url); + qt_sendSpontaneousEvent(qAppInstance(), &qtEvent); +} + @end #endif diff --git a/src/gui/kernel/qcocoaapplicationdelegate_mac_p.h b/src/gui/kernel/qcocoaapplicationdelegate_mac_p.h index 80df645..a137744 100644 --- a/src/gui/kernel/qcocoaapplicationdelegate_mac_p.h +++ b/src/gui/kernel/qcocoaapplicationdelegate_mac_p.h @@ -123,5 +123,6 @@ QT_FORWARD_DECLARE_CLASS(QApplicationPrivate); - (void)setMenuLoader:(QT_MANGLE_NAMESPACE(QCocoaMenuLoader)*)menuLoader; - (QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *)menuLoader; - (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate; +- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent; @end #endif diff --git a/src/gui/kernel/qcocoawindowdelegate_mac.mm b/src/gui/kernel/qcocoawindowdelegate_mac.mm index 803a1b1..9fb674e 100644 --- a/src/gui/kernel/qcocoawindowdelegate_mac.mm +++ b/src/gui/kernel/qcocoawindowdelegate_mac.mm @@ -307,6 +307,18 @@ static void cleanupCocoaWindowDelegate() return m_windowHash->value(window); } +- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame +{ + Q_UNUSED(newFrame); + // saving the current window geometry before the window is maximized + QWidget *qwidget = m_windowHash->value(window); + if (qwidget->isWindow() && !(qwidget->windowState() & Qt::WindowMaximized)) { + QWidgetPrivate *widgetPrivate = qt_widget_private(qwidget); + widgetPrivate->topData()->normalGeometry = qwidget->geometry(); + } + return YES; +} + - (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)defaultFrame { NSRect frameToReturn = defaultFrame; diff --git a/src/gui/kernel/qcocoawindowdelegate_mac_p.h b/src/gui/kernel/qcocoawindowdelegate_mac_p.h index 3728002..243ba03 100644 --- a/src/gui/kernel/qcocoawindowdelegate_mac_p.h +++ b/src/gui/kernel/qcocoawindowdelegate_mac_p.h @@ -78,6 +78,7 @@ QT_FORWARD_DECLARE_CLASS(QWidgetData) - (void)windowDidResignKey:(NSNotification*)notification; - (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu; - (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard; +- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame; @end @protocol NSDrawerDelegate <NSObject> diff --git a/src/gui/kernel/qdesktopwidget_mac.mm b/src/gui/kernel/qdesktopwidget_mac.mm index 88dc173..c2d05d7 100644 --- a/src/gui/kernel/qdesktopwidget_mac.mm +++ b/src/gui/kernel/qdesktopwidget_mac.mm @@ -136,16 +136,19 @@ void QDesktopWidgetImplementation::onResize() screenRects.clear(); availableRects.clear(); NSRect primaryRect = [[displays objectAtIndex:0] frame]; - for (int i = 0; i<screenCount; i++) { - NSRect r = [[displays objectAtIndex:i] frame]; - const int flippedY = - r.origin.y + // account for position offset and + for (int i = 0; i<screenCount; i++) { + NSRect r = [[displays objectAtIndex:i] frame]; + int flippedY = - r.origin.y + // account for position offset and primaryRect.size.height - r.size.height; // height difference. screenRects.append(QRectF(r.origin.x, flippedY, r.size.width, r.size.height)); - r = [[displays objectAtIndex:i] visibleFrame]; + + r = [[displays objectAtIndex:i] visibleFrame]; + flippedY = - r.origin.y + // account for position offset and + primaryRect.size.height - r.size.height; // height difference. availableRects.append(QRectF(r.origin.x, flippedY, r.size.width, r.size.height)); - } + } } diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index ad68aea..ff97405 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -2976,13 +2976,13 @@ QShowEvent::~QShowEvent() /*! \class QFileOpenEvent \brief The QFileOpenEvent class provides an event that will be - sent when there is a request to open a file. + sent when there is a request to open a file or a URL. \ingroup events File open events will be sent to the QApplication::instance() - when the operating system requests that a file be opened. This is - a high-level event that can be caused by different user actions + when the operating system requests that a file or URL should be opened. + This is a high-level event that can be caused by different user actions depending on the user's desktop environment; for example, double clicking on an file icon in the Finder on Mac OS X. @@ -2999,12 +2999,27 @@ QShowEvent::~QShowEvent() */ QFileOpenEvent::QFileOpenEvent(const QString &file) : QEvent(FileOpen), f(file) -{} +{ + d = reinterpret_cast<QEventPrivate *>(new QFileOpenEventPrivate(QUrl::fromLocalFile(file))); +} + +/*! + \internal + + Constructs a file open event for the given \a url. +*/ +QFileOpenEvent::QFileOpenEvent(const QUrl &url) + : QEvent(FileOpen) +{ + d = reinterpret_cast<QEventPrivate *>(new QFileOpenEventPrivate(url)); + f = url.toLocalFile(); +} /*! \internal */ QFileOpenEvent::~QFileOpenEvent() { + delete reinterpret_cast<QFileOpenEventPrivate *>(d); } /*! @@ -3013,6 +3028,16 @@ QFileOpenEvent::~QFileOpenEvent() Returns the file that is being opened. */ +/*! + \fn QUrl QFileOpenEvent::url() const + + Returns the url that is being opened. +*/ +QUrl QFileOpenEvent::url() const +{ + return reinterpret_cast<const QFileOpenEventPrivate *>(d)->url; +} + #ifndef QT_NO_TOOLBAR /*! \internal diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index b9512fa..9839269 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -638,9 +638,11 @@ class Q_GUI_EXPORT QFileOpenEvent : public QEvent { public: QFileOpenEvent(const QString &file); + QFileOpenEvent(const QUrl &url); ~QFileOpenEvent(); inline QString file() const { return f; } + QUrl url() const; private: QString f; }; diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h index 6e6ab01..4aaaa8b 100644 --- a/src/gui/kernel/qevent_p.h +++ b/src/gui/kernel/qevent_p.h @@ -43,6 +43,7 @@ #define QEVENT_P_H #include <QtCore/qglobal.h> +#include <QtCore/qurl.h> #include <QtGui/qevent.h> QT_BEGIN_NAMESPACE @@ -164,6 +165,18 @@ public: QMap<Qt::GestureType, QWidget *> targetWidgets; }; + +class QFileOpenEventPrivate +{ +public: + inline QFileOpenEventPrivate(const QUrl &url) + : url(url) + { + } + + QUrl url; +}; + QT_END_NAMESPACE #endif // QEVENT_P_H diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp index 4edf8a9..e8c2f8a 100644 --- a/src/gui/kernel/qgesture.cpp +++ b/src/gui/kernel/qgesture.cpp @@ -220,15 +220,6 @@ QGesture::GestureCancelPolicy QGesture::gestureCancelPolicy() const */ /*! - \property QPanGesture::totalOffset - \brief the total offset from the first input position to the current input - position - - The total offset measures the total change in position of the user's input - covered by the gesture on the input device. -*/ - -/*! \property QPanGesture::lastOffset \brief the last offset recorded for this gesture @@ -667,4 +658,70 @@ void QSwipeGesture::setSwipeAngle(qreal value) d_func()->swipeAngle = value; } +/*! + \class QTapGesture + \since 4.6 + \brief The QTapGesture class describes a tap gesture made by the user. + \ingroup gestures + + \sa {Gestures Programming}, QPanGesture, QPinchGesture +*/ + +/*! + \property QTapGesture::position + \brief the position of the tap +*/ + +/*! + \internal +*/ +QTapGesture::QTapGesture(QObject *parent) + : QGesture(*new QTapGesturePrivate, parent) +{ + d_func()->gestureType = Qt::TapGesture; +} + +QPointF QTapGesture::position() const +{ + return d_func()->position; +} + +void QTapGesture::setPosition(const QPointF &value) +{ + d_func()->position = value; +} +/*! + \class QTapAndHoldGesture + \since 4.6 + \brief The QTapAndHoldGesture class describes a tap-and-hold (aka LongTap) + gesture made by the user. + \ingroup gestures + + \sa {Gestures Programming}, QPanGesture, QPinchGesture +*/ + +/*! + \property QTapAndHoldGesture::position + \brief the position of the tap +*/ + +/*! + \internal +*/ +QTapAndHoldGesture::QTapAndHoldGesture(QObject *parent) + : QGesture(*new QTapAndHoldGesturePrivate, parent) +{ + d_func()->gestureType = Qt::TapAndHoldGesture; +} + +QPointF QTapAndHoldGesture::position() const +{ + return d_func()->position; +} + +void QTapAndHoldGesture::setPosition(const QPointF &value) +{ + d_func()->position = value; +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h index dd322ad..f995d7b 100644 --- a/src/gui/kernel/qgesture.h +++ b/src/gui/kernel/qgesture.h @@ -219,6 +219,40 @@ public: friend class QSwipeGestureRecognizer; }; +class QTapGesturePrivate; +class Q_GUI_EXPORT QTapGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QTapGesture) + + Q_PROPERTY(QPointF position READ position WRITE setPosition) + +public: + QTapGesture(QObject *parent = 0); + + QPointF position() const; + void setPosition(const QPointF &pos); + + friend class QTapGestureRecognizer; +}; + +class QTapAndHoldGesturePrivate; +class Q_GUI_EXPORT QTapAndHoldGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QTapAndHoldGesture) + + Q_PROPERTY(QPointF position READ position WRITE setPosition) + +public: + QTapAndHoldGesture(QObject *parent = 0); + + QPointF position() const; + void setPosition(const QPointF &pos); + + friend class QTapAndHoldGestureRecognizer; +}; + QT_END_NAMESPACE Q_DECLARE_METATYPE(QGesture::GestureCancelPolicy) diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h index ae2e287..2537f47 100644 --- a/src/gui/kernel/qgesture_p.h +++ b/src/gui/kernel/qgesture_p.h @@ -136,13 +136,45 @@ public: QSwipeGesturePrivate() : horizontalDirection(QSwipeGesture::NoDirection), verticalDirection(QSwipeGesture::NoDirection), - swipeAngle(0) + swipeAngle(0), + started(false), speed(0) { } QSwipeGesture::SwipeDirection horizontalDirection; QSwipeGesture::SwipeDirection verticalDirection; qreal swipeAngle; + + QPoint lastPositions[3]; + bool started; + qreal speed; + QTime time; +}; + +class QTapGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QTapGesture) + +public: + QTapGesturePrivate() + { + } + + QPointF position; +}; + +class QTapAndHoldGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QTapAndHoldGesture) + +public: + QTapAndHoldGesturePrivate() + : timerId(0) + { + } + + QPointF position; + int timerId; }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp index 628892d..abd2128 100644 --- a/src/gui/kernel/qgesturemanager.cpp +++ b/src/gui/kernel/qgesturemanager.cpp @@ -90,9 +90,13 @@ QGestureManager::QGestureManager(QObject *parent) #else registerGestureRecognizer(new QPanGestureRecognizer); registerGestureRecognizer(new QPinchGestureRecognizer); + registerGestureRecognizer(new QSwipeGestureRecognizer); + registerGestureRecognizer(new QTapGestureRecognizer); +#endif #if defined(Q_OS_WIN) registerGestureRecognizer(new QWinNativePanGestureRecognizer); -#endif +#else + registerGestureRecognizer(new QTapAndHoldGestureRecognizer); #endif } @@ -175,8 +179,10 @@ QGesture *QGestureManager::getState(QObject *object, QGestureRecognizer *recogni return 0; } else if (QGesture *g = qobject_cast<QGesture *>(object)) { return g; +#ifndef QT_NO_GRAPHICSVIEW } else { Q_ASSERT(qobject_cast<QGraphicsObject *>(object)); +#endif } QList<QGesture *> states = diff --git a/src/gui/kernel/qmacgesturerecognizer_mac.mm b/src/gui/kernel/qmacgesturerecognizer_mac.mm index d842322..f142d71 100644 --- a/src/gui/kernel/qmacgesturerecognizer_mac.mm +++ b/src/gui/kernel/qmacgesturerecognizer_mac.mm @@ -120,7 +120,7 @@ QMacPinchGestureRecognizer::recognize(QGesture *gesture, QObject *obj, QEvent *e case QNativeGestureEvent::Zoom: g->setLastScaleFactor(g->scaleFactor()); g->setLastRotationAngle(g->rotationAngle()); - g->setScaleFactor(g->scaleFactor() + ev->percentage); + g->setScaleFactor(g->scaleFactor() * (1 + ev->percentage)); g->setChangeFlags(QPinchGesture::ScaleFactorChanged); g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags()); return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint; diff --git a/src/gui/kernel/qsoftkeymanager.cpp b/src/gui/kernel/qsoftkeymanager.cpp index a914220..ecad72f 100644 --- a/src/gui/kernel/qsoftkeymanager.cpp +++ b/src/gui/kernel/qsoftkeymanager.cpp @@ -137,12 +137,14 @@ QAction *QSoftKeyManager::createAction(StandardSoftKey standardKey, QWidget *act */ QAction *QSoftKeyManager::createKeyedAction(StandardSoftKey standardKey, Qt::Key key, QWidget *actionWidget) { +#ifndef QT_NO_ACTION QScopedPointer<QAction> action(createAction(standardKey, actionWidget)); connect(action.data(), SIGNAL(triggered()), QSoftKeyManager::instance(), SLOT(sendKeyEvent())); connect(action.data(), SIGNAL(destroyed(QObject*)), QSoftKeyManager::instance(), SLOT(cleanupHash(QObject*))); QSoftKeyManager::instance()->d_func()->keyedActions.insert(action.data(), key); return action.take(); +#endif //QT_NO_ACTION } void QSoftKeyManager::cleanupHash(QObject* obj) @@ -175,6 +177,7 @@ void QSoftKeyManager::updateSoftKeys() bool QSoftKeyManager::event(QEvent *e) { +#ifndef QT_NO_ACTION if (e->type() == QEvent::UpdateSoftKeys) { QList<QAction*> softKeys; QWidget *source = QApplication::focusWidget(); @@ -200,6 +203,7 @@ bool QSoftKeyManager::event(QEvent *e) QSoftKeyManagerPrivate::updateSoftKeys_sys(softKeys); return true; } +#endif //QT_NO_ACTION return false; } diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp index dfd49eb..0ea4764 100644 --- a/src/gui/kernel/qstandardgestures.cpp +++ b/src/gui/kernel/qstandardgestures.cpp @@ -45,6 +45,7 @@ #include "qevent.h" #include "qwidget.h" #include "qabstractscrollarea.h" +#include "qdebug.h" QT_BEGIN_NAMESPACE @@ -66,7 +67,9 @@ QGesture *QPanGestureRecognizer::create(QObject *target) return new QPanGesture; } -QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state, QObject *, QEvent *event) +QGestureRecognizer::Result QPanGestureRecognizer::recognize(QGesture *state, + QObject *, + QEvent *event) { QPanGesture *q = static_cast<QPanGesture *>(state); QPanGesturePrivate *d = q->d_func(); @@ -155,7 +158,9 @@ QGesture *QPinchGestureRecognizer::create(QObject *target) return new QPinchGesture; } -QGestureRecognizer::Result QPinchGestureRecognizer::recognize(QGesture *state, QObject *, QEvent *event) +QGestureRecognizer::Result QPinchGestureRecognizer::recognize(QGesture *state, + QObject *, + QEvent *event) { QPinchGesture *q = static_cast<QPinchGesture *>(state); QPinchGesturePrivate *d = q->d_func(); @@ -199,8 +204,9 @@ QGestureRecognizer::Result QPinchGestureRecognizer::recognize(QGesture *state, Q d->centerPoint = centerPoint; d->changeFlags |= QPinchGesture::CenterPointChanged; - const qreal scaleFactor = QLineF(p1.pos(), p2.pos()).length() - / QLineF(d->startPosition[0], d->startPosition[1]).length(); + const qreal scaleFactor = + QLineF(p1.screenPos(), p2.screenPos()).length() + / QLineF(d->startPosition[0], d->startPosition[1]).length(); if (d->isNewSequence) { d->lastScaleFactor = scaleFactor; } else { @@ -210,7 +216,13 @@ QGestureRecognizer::Result QPinchGestureRecognizer::recognize(QGesture *state, Q d->totalScaleFactor += d->scaleFactor - d->lastScaleFactor; d->changeFlags |= QPinchGesture::ScaleFactorChanged; - const qreal rotationAngle = -line.angle(); + qreal angle = QLineF(p1.screenPos(), p2.screenPos()).angle(); + if (angle > 180) + angle -= 360; + qreal startAngle = QLineF(p1.startScreenPos(), p2.startScreenPos()).angle(); + if (startAngle > 180) + startAngle -= 360; + const qreal rotationAngle = startAngle - angle; if (d->isNewSequence) d->lastRotationAngle = rotationAngle; else @@ -224,7 +236,10 @@ QGestureRecognizer::Result QPinchGestureRecognizer::recognize(QGesture *state, Q result = QGestureRecognizer::TriggerGesture; } else { d->isNewSequence = true; - result = QGestureRecognizer::MayBeGesture; + if (q->state() == Qt::NoGesture) + result = QGestureRecognizer::Ignore; + else + result = QGestureRecognizer::FinishGesture; } break; } @@ -252,6 +267,299 @@ void QPinchGestureRecognizer::reset(QGesture *state) d->totalRotationAngle = d->lastRotationAngle = d->rotationAngle = 0; d->isNewSequence = true; + d->startPosition[0] = d->startPosition[1] = QPointF(); + + QGestureRecognizer::reset(state); +} + +// +// QSwipeGestureRecognizer +// + +QSwipeGestureRecognizer::QSwipeGestureRecognizer() +{ +} + +QGesture *QSwipeGestureRecognizer::create(QObject *target) +{ + if (target && target->isWidgetType()) { + static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents); + } + return new QSwipeGesture; +} + +QGestureRecognizer::Result QSwipeGestureRecognizer::recognize(QGesture *state, + QObject *, + QEvent *event) +{ + QSwipeGesture *q = static_cast<QSwipeGesture *>(state); + QSwipeGesturePrivate *d = q->d_func(); + + const QTouchEvent *ev = static_cast<const QTouchEvent *>(event); + + QGestureRecognizer::Result result; + + switch (event->type()) { + case QEvent::TouchBegin: { + d->speed = 1; + d->time = QTime::currentTime(); + d->started = true; + result = QGestureRecognizer::MayBeGesture; + break; + } + case QEvent::TouchEnd: { + if (q->state() != Qt::NoGesture) { + result = QGestureRecognizer::FinishGesture; + } else { + result = QGestureRecognizer::CancelGesture; + } + break; + } + case QEvent::TouchUpdate: { + if (!d->started) + result = QGestureRecognizer::CancelGesture; + else if (ev->touchPoints().size() == 3) { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); + QTouchEvent::TouchPoint p3 = ev->touchPoints().at(2); + + if (d->lastPositions[0].isNull()) { + d->lastPositions[0] = p1.startScreenPos().toPoint(); + d->lastPositions[1] = p2.startScreenPos().toPoint(); + d->lastPositions[2] = p3.startScreenPos().toPoint(); + } + d->hotSpot = p1.screenPos(); + d->isHotSpotSet = true; + + int xDistance = (p1.screenPos().x() - d->lastPositions[0].x() + + p2.screenPos().x() - d->lastPositions[1].x() + + p3.screenPos().x() - d->lastPositions[2].x()) / 3; + int yDistance = (p1.screenPos().y() - d->lastPositions[0].y() + + p2.screenPos().y() - d->lastPositions[1].y() + + p3.screenPos().y() - d->lastPositions[2].y()) / 3; + + const int distance = xDistance >= yDistance ? xDistance : yDistance; + int elapsedTime = d->time.msecsTo(QTime::currentTime()); + if (!elapsedTime) + elapsedTime = 1; + d->speed = 0.9 * d->speed + distance / elapsedTime; + d->time = QTime::currentTime(); + d->swipeAngle = QLineF(p1.startScreenPos(), p1.screenPos()).angle(); + + static const int MoveThreshold = 50; + if (xDistance > MoveThreshold || yDistance > MoveThreshold) { + // measure the distance to check if the direction changed + d->lastPositions[0] = p1.screenPos().toPoint(); + d->lastPositions[1] = p2.screenPos().toPoint(); + d->lastPositions[2] = p3.screenPos().toPoint(); + QSwipeGesture::SwipeDirection horizontal = + xDistance > 0 ? QSwipeGesture::Right : QSwipeGesture::Left; + QSwipeGesture::SwipeDirection vertical = + yDistance > 0 ? QSwipeGesture::Down : QSwipeGesture::Up; + if (d->verticalDirection == QSwipeGesture::NoDirection) + d->verticalDirection = vertical; + if (d->horizontalDirection == QSwipeGesture::NoDirection) + d->horizontalDirection = horizontal; + if (d->verticalDirection != vertical || d->horizontalDirection != horizontal) { + // the user has changed the direction! + result = QGestureRecognizer::CancelGesture; + } + result = QGestureRecognizer::TriggerGesture; + } else { + if (q->state() != Qt::NoGesture) + result = QGestureRecognizer::TriggerGesture; + else + result = QGestureRecognizer::MayBeGesture; + } + } else if (ev->touchPoints().size() > 3) { + result = QGestureRecognizer::CancelGesture; + } else { // less than 3 touch points + if (d->started && (ev->touchPointStates() & Qt::TouchPointPressed)) + result = QGestureRecognizer::CancelGesture; + else if (d->started) + result = QGestureRecognizer::Ignore; + else + result = QGestureRecognizer::MayBeGesture; + } + break; + } + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + result = QGestureRecognizer::Ignore; + break; + default: + result = QGestureRecognizer::Ignore; + break; + } + return result; +} + +void QSwipeGestureRecognizer::reset(QGesture *state) +{ + QSwipeGesture *q = static_cast<QSwipeGesture *>(state); + QSwipeGesturePrivate *d = q->d_func(); + + d->verticalDirection = d->horizontalDirection = QSwipeGesture::NoDirection; + d->swipeAngle = 0; + + d->lastPositions[0] = d->lastPositions[1] = d->lastPositions[2] = QPoint(); + d->started = false; + d->speed = 0; + d->time = QTime(); + + QGestureRecognizer::reset(state); +} + +// +// QTapGestureRecognizer +// + +QTapGestureRecognizer::QTapGestureRecognizer() +{ +} + +QGesture *QTapGestureRecognizer::create(QObject *target) +{ + if (target && target->isWidgetType()) { + static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents); + } + return new QTapGesture; +} + +QGestureRecognizer::Result QTapGestureRecognizer::recognize(QGesture *state, + QObject *, + QEvent *event) +{ + QTapGesture *q = static_cast<QTapGesture *>(state); + QTapGesturePrivate *d = q->d_func(); + + const QTouchEvent *ev = static_cast<const QTouchEvent *>(event); + + QGestureRecognizer::Result result = QGestureRecognizer::CancelGesture; + + switch (event->type()) { + case QEvent::TouchBegin: { + d->position = ev->touchPoints().at(0).pos(); + result = QGestureRecognizer::TriggerGesture; + break; + } + case QEvent::TouchUpdate: + case QEvent::TouchEnd: { + if (q->state() != Qt::NoGesture && ev->touchPoints().size() == 1) { + QTouchEvent::TouchPoint p = ev->touchPoints().at(0); + QPoint delta = p.pos().toPoint() - p.startPos().toPoint(); + enum { TapRadius = 40 }; + if (delta.manhattanLength() <= TapRadius) { + if (event->type() == QEvent::TouchEnd) + result = QGestureRecognizer::FinishGesture; + else + result = QGestureRecognizer::TriggerGesture; + } + } + break; + } + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + result = QGestureRecognizer::Ignore; + break; + default: + result = QGestureRecognizer::Ignore; + break; + } + return result; +} + +void QTapGestureRecognizer::reset(QGesture *state) +{ + QTapGesture *q = static_cast<QTapGesture *>(state); + QTapGesturePrivate *d = q->d_func(); + + d->position = QPointF(); + + QGestureRecognizer::reset(state); +} + +// +// QTapAndHoldGestureRecognizer +// + +QTapAndHoldGestureRecognizer::QTapAndHoldGestureRecognizer() +{ +} + +QGesture *QTapAndHoldGestureRecognizer::create(QObject *target) +{ + if (target && target->isWidgetType()) { + static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents); + } + return new QTapAndHoldGesture; +} + +QGestureRecognizer::Result +QTapAndHoldGestureRecognizer::recognize(QGesture *state, QObject *object, + QEvent *event) +{ + QTapAndHoldGesture *q = static_cast<QTapAndHoldGesture *>(state); + QTapAndHoldGesturePrivate *d = q->d_func(); + + if (object == state && event->type() == QEvent::Timer) { + q->killTimer(d->timerId); + d->timerId = 0; + return QGestureRecognizer::Ignore | QGestureRecognizer::ConsumeEventHint; + } + + const QTouchEvent *ev = static_cast<const QTouchEvent *>(event); + + QGestureRecognizer::Result result = QGestureRecognizer::CancelGesture; + + enum { TimerInterval = 2000 }; + enum { TapRadius = 40 }; + + switch (event->type()) { + case QEvent::TouchBegin: + d->position = ev->touchPoints().at(0).pos(); + if (d->timerId) + q->killTimer(d->timerId); + d->timerId = q->startTimer(TimerInterval); + result = QGestureRecognizer::TriggerGesture; + break; + case QEvent::TouchEnd: + if (d->timerId) + result = QGestureRecognizer::CancelGesture; + else + result = QGestureRecognizer::FinishGesture; + break; + case QEvent::TouchUpdate: + if (q->state() != Qt::NoGesture && ev->touchPoints().size() == 1) { + QTouchEvent::TouchPoint p = ev->touchPoints().at(0); + QPoint delta = p.pos().toPoint() - p.startPos().toPoint(); + if (delta.manhattanLength() <= TapRadius) + result = QGestureRecognizer::TriggerGesture; + } + break; + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + result = QGestureRecognizer::Ignore; + break; + default: + result = QGestureRecognizer::Ignore; + break; + } + return result; +} + +void QTapAndHoldGestureRecognizer::reset(QGesture *state) +{ + QTapAndHoldGesture *q = static_cast<QTapAndHoldGesture *>(state); + QTapAndHoldGesturePrivate *d = q->d_func(); + + d->position = QPointF(); + if (d->timerId) + q->killTimer(d->timerId); + d->timerId = 0; QGestureRecognizer::reset(state); } diff --git a/src/gui/kernel/qstandardgestures_p.h b/src/gui/kernel/qstandardgestures_p.h index e6f346c..8fea2bc 100644 --- a/src/gui/kernel/qstandardgestures_p.h +++ b/src/gui/kernel/qstandardgestures_p.h @@ -74,7 +74,36 @@ public: QPinchGestureRecognizer(); QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +class QSwipeGestureRecognizer : public QGestureRecognizer +{ +public: + QSwipeGestureRecognizer(); + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +class QTapGestureRecognizer : public QGestureRecognizer +{ +public: + QTapGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +class QTapAndHoldGestureRecognizer : public QGestureRecognizer +{ +public: + QTapAndHoldGestureRecognizer(); + + QGesture *create(QObject *target); QGestureRecognizer::Result recognize(QGesture *state, QObject *watched, QEvent *event); void reset(QGesture *state); }; diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 386bf71..271b939 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -5171,8 +5171,7 @@ void QWidgetPrivate::render_helper(QPainter *painter, const QPoint &targetOffset return; QPixmap pixmap(size); - if (!(renderFlags & QWidget::DrawWindowBackground) - || !q->palette().brush(q->backgroundRole()).isOpaque()) + if (!(renderFlags & QWidget::DrawWindowBackground) || !isOpaque) pixmap.fill(Qt::transparent); q->render(&pixmap, QPoint(), toBePainted, renderFlags); diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 278bd80..75f9a59 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -730,6 +730,7 @@ static EventTypeSpec window_events[] = { { kEventClassWindow, kEventWindowClose }, { kEventClassWindow, kEventWindowExpanded }, { kEventClassWindow, kEventWindowHidden }, + { kEventClassWindow, kEventWindowZoom }, { kEventClassWindow, kEventWindowZoomed }, { kEventClassWindow, kEventWindowCollapsed }, { kEventClassWindow, kEventWindowToolbarSwitchMode }, @@ -812,6 +813,9 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event, QShowEvent qse; QApplication::sendSpontaneousEvent(widget, &qse); + } else if(ekind == kEventWindowZoom) { + widget->d_func()->topData()->normalGeometry = widget->geometry(); + handled_event = false; } else if(ekind == kEventWindowZoomed) { WindowPartCode windowPart; GetEventParameter(event, kEventParamWindowPartCode, @@ -3487,10 +3491,10 @@ void QWidget::setWindowState(Qt::WindowStates newstate) qt_mac_set_fullscreen_mode(true); } else { needShow = isVisible(); - setParent(parentWidget(), d->topData()->savedFlags); - setGeometry(d->topData()->normalGeometry); if(!qApp->desktop()->screenNumber(this)) qt_mac_set_fullscreen_mode(false); + setParent(parentWidget(), d->topData()->savedFlags); + setGeometry(d->topData()->normalGeometry); d->topData()->normalGeometry.setRect(0, 0, -1, -1); } } @@ -3592,7 +3596,7 @@ void QWidget::setWindowState(Qt::WindowStates newstate) [window zoom:window]; #endif needSendStateChange = oldstate == windowState(); // Zoom didn't change flags. - } else if(oldstate & Qt::WindowMaximized) { + } else if(oldstate & Qt::WindowMaximized && !(oldstate & Qt::WindowFullScreen)) { #ifndef QT_MAC_USE_COCOA Point idealSize; ZoomWindowIdeal(window, inZoomIn, &idealSize); diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index 22a94b9..b7ba273 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -677,7 +677,11 @@ QPoint QWidget::mapToGlobal(const QPoint &pos) const QWidget *parentWindow = window(); QWExtra *extra = parentWindow->d_func()->extra; if (!isVisible() || parentWindow->isMinimized() || !testAttribute(Qt::WA_WState_Created) || !internalWinId() - || (extra && extra->proxyWidget)) { + || (extra +#ifndef QT_NO_GRAPHICSVIEW + && extra->proxyWidget +#endif //QT_NO_GRAPHICSVIEW + )) { if (extra && extra->topextra && extra->topextra->embedded) { QPoint pt = mapTo(parentWindow, pos); POINT p = {pt.x(), pt.y()}; @@ -704,7 +708,11 @@ QPoint QWidget::mapFromGlobal(const QPoint &pos) const QWidget *parentWindow = window(); QWExtra *extra = parentWindow->d_func()->extra; if (!isVisible() || parentWindow->isMinimized() || !testAttribute(Qt::WA_WState_Created) || !internalWinId() - || (extra && extra->proxyWidget)) { + || (extra +#ifndef QT_NO_GRAPHICSVIEW + && extra->proxyWidget +#endif //QT_NO_GRAPHICSVIEW + )) { if (extra && extra->topextra && extra->topextra->embedded) { POINT p = {pos.x(), pos.y()}; ScreenToClient(parentWindow->effectiveWinId(), &p); @@ -1331,8 +1339,15 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) if (isResize && !q->testAttribute(Qt::WA_StaticContents) && q->internalWinId()) ValidateRgn(q->internalWinId(), 0); +#ifdef Q_WS_WINCE + // On Windows CE we can't just fiddle around with the window state. + // Too much magic in setWindowState. + if (isResize && q->isMaximized()) + q->setWindowState(q->windowState() & ~Qt::WindowMaximized); +#else if (isResize) data.window_state &= ~Qt::WindowMaximized; +#endif if (data.window_state & Qt::WindowFullScreen) { QTLWExtra *top = topData(); @@ -2042,6 +2057,7 @@ void QWidgetPrivate::winSetupGestures() bool needv = false; bool singleFingerPanEnabled = false; +#ifndef QT_NO_SCROLLAREA if (QAbstractScrollArea *asa = qobject_cast<QAbstractScrollArea*>(q->parent())) { QScrollBar *hbar = asa->horizontalScrollBar(); QScrollBar *vbar = asa->verticalScrollBar(); @@ -2055,6 +2071,7 @@ void QWidgetPrivate::winSetupGestures() if (!winid) winid = q->winId(); // enforces the native winid on the viewport } +#endif //QT_NO_SCROLLAREA if (winid && qAppPriv->SetGestureConfig) { GESTURECONFIG gc[1]; memset(gc, 0, sizeof(gc)); diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index 76d50db..2d434d3 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -223,11 +223,23 @@ void qt_scale_image_16bit(uchar *destPixels, int dbpl, int h = ty2 - ty1; int w = tx2 - tx1; - const int dstx = qCeil((tx1 + qreal(0.5) - qMin(targetRect.left(), targetRect.right())) * ix) - 1; - const int dsty = qCeil((ty1 + qreal(0.5) - qMin(targetRect.top(), targetRect.bottom())) * iy) - 1; + quint32 basex; + quint32 srcy; - quint32 basex = quint32((sx < 0 ? srcRect.right() : srcRect.left()) * 65536) + dstx; - quint32 srcy = quint32((sy < 0 ? srcRect.bottom() : srcRect.top()) * 65536) + dsty; + if (sx < 0) { + int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1; + basex = quint32(srcRect.right() * 65536) + dstx; + } else { + int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1; + basex = quint32(srcRect.left() * 65536) + dstx; + } + if (sy < 0) { + int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1; + srcy = quint32(srcRect.bottom() * 65536) + dsty; + } else { + int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1; + srcy = quint32(srcRect.top() * 65536) + dsty; + } quint16 *dst = ((quint16 *) (destPixels + ty1 * dbpl)) + tx1; @@ -723,11 +735,23 @@ template <typename T> void qt_scale_image_32bit(uchar *destPixels, int dbpl, int h = ty2 - ty1; int w = tx2 - tx1; - const int dstx = qCeil((tx1 + qreal(0.5) - qMin(targetRect.left(), targetRect.right())) * ix) - 1; - const int dsty = qCeil((ty1 + qreal(0.5) - qMin(targetRect.top(), targetRect.bottom())) * iy) - 1; + quint32 basex; + quint32 srcy; - quint32 basex = quint32((sx < 0 ? srcRect.right() : srcRect.left()) * 65536) + dstx; - quint32 srcy = quint32((sy < 0 ? srcRect.bottom() : srcRect.top()) * 65536) + dsty; + if (sx < 0) { + int dstx = qFloor((tx1 + qreal(0.5) - targetRect.right()) * ix) + 1; + basex = quint32(srcRect.right() * 65536) + dstx; + } else { + int dstx = qCeil((tx1 + qreal(0.5) - targetRect.left()) * ix) - 1; + basex = quint32(srcRect.left() * 65536) + dstx; + } + if (sy < 0) { + int dsty = qFloor((ty1 + qreal(0.5) - targetRect.bottom()) * iy) + 1; + srcy = quint32(srcRect.bottom() * 65536) + dsty; + } else { + int dsty = qCeil((ty1 + qreal(0.5) - targetRect.top()) * iy) - 1; + srcy = quint32(srcRect.top() * 65536) + dsty; + } quint32 *dst = ((quint32 *) (destPixels + ty1 * dbpl)) + tx1; diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index 6982f22..ecbb290 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -970,7 +970,29 @@ bool QBrush::operator==(const QBrush &b) const QDebug operator<<(QDebug dbg, const QBrush &b) { #ifndef Q_BROKEN_DEBUG_STREAM - dbg.nospace() << "QBrush(" << b.color() << ',' << b.style() << ')'; + char *BRUSH_STYLES[] = { + "NoBrush", + "SolidPattern", + "Dense1Pattern", + "Dense2Pattern", + "Dense3Pattern", + "Dense4Pattern", + "Dense5Pattern", + "Dense6Pattern", + "Dense7Pattern", + "HorPattern", + "VerPattern", + "CrossPattern", + "BDiagPattern", + "FDiagPattern", + "DiagCrossPattern", + "LinearGradientPattern", + "RadialGradientPattern", + "ConicalGradientPattern", + "TexturePattern" + }; + + dbg.nospace() << "QBrush(" << b.color() << ',' << BRUSH_STYLES[b.style()] << ')'; return dbg.space(); #else qWarning("This compiler doesn't support streaming QBrush to QDebug"); diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index b9f439e..8d7a15d 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -2386,12 +2386,12 @@ static void QT_FASTCALL comp_func_HardLight(uint *dest, const uint *src, int len } /* - if 2.Sca < Sa - Dca' = Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise if 8.Dca <= Da - Dca' = Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa).(3 - 8.Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = (Dca.Sa + ((Dca/Da)^(0.5).Da - Dca).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa) + if 2.Sca <= Sa + Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise if 2.Sca > Sa and 4.Dca <= Da + Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise if 2.Sca > Sa and 4.Dca > Da + Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) */ static inline int soft_light_op(int dst, int src, int da, int sa) { @@ -2400,13 +2400,11 @@ static inline int soft_light_op(int dst, int src, int da, int sa) const int temp = (src * (255 - da) + dst * (255 - sa)) * 255; if (src2 < sa) - return (dst * ((sa * 255) - (255 - dst_np) * (src2 - sa)) + temp) / 65025; - else if (8 * dst <= da) - return (dst * ((sa * 255) - ((255 - dst_np) * (src2 - sa) * ((3 * 255) - 8 * dst_np)) / 255) + temp) / 65025; + return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025; + else if (4 * dst <= da) + return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025; else { - // sqrt is too expensive to do three times per pixel, so skipping it for now - // a future possibility is to use a LUT - return ((dst * sa * 255) + (int(dst_np) * da - (dst * 255)) * (src2 - sa) + temp) / 65025; + return (dst * sa * 255 + da * (src2 - sa) * (int(sqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025; } } diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index a323a43..fc6726e 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -48,7 +48,7 @@ #include <QDebug> -//#define QPAINTBUFFER_DEBUG_DRAW +// #define QPAINTBUFFER_DEBUG_DRAW QT_BEGIN_NAMESPACE @@ -247,23 +247,24 @@ void QPaintBuffer::draw(QPainter *painter, int frame) const #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBuffer::draw() --------------------------------"; -// printf("Float buffer:"); -// for (int i=0; i<d->floats.size(); i++) { -// if ((i % 10) == 0) { -// printf("\n%4d-%4d: ", i, i+9); -// } -// printf("%4.2f ", d->floats[i]); -// } -// printf("\n"); - -// printf("Int Buffer:"); -// for (int i=0; i<d->ints.size(); i++) { -// if ((i % 10) == 0) { -// printf("\n%4d-%4d: ", i, i+10); -// } -// printf("%5d", d->ints[i]); -// } -// printf("\n"); + Q_D(const QPaintBuffer); + printf("Float buffer:"); + for (int i=0; i<d->floats.size(); i++) { + if ((i % 10) == 0) { + printf("\n%4d-%4d: ", i, i+9); + } + printf("%4.2f ", d->floats[i]); + } + printf("\n"); + + printf("Int Buffer:"); + for (int i=0; i<d->ints.size(); i++) { + if ((i % 10) == 0) { + printf("\n%4d-%4d: ", i, i+10); + } + printf("%5d", d->ints[i]); + } + printf("\n"); #endif if (painter && !painter->isActive()) @@ -406,16 +407,17 @@ void QPaintBufferEngine::clipEnabledChanged() void QPaintBufferEngine::penChanged() { -#ifdef QPAINTBUFFER_DEBUG_DRAW - qDebug() << "QPaintBufferEngine:" << state()->pen; -#endif const QPen &pen = state()->pen; if (!buffer->commands.isEmpty() && buffer->commands.last().id == QPaintBufferPrivate::Cmd_SetPen) { +#ifdef QPAINTBUFFER_DEBUG_DRAW + qDebug() << "QPaintBufferEngine: penChanged (compressed)" << state()->pen; +#endif buffer->variants[buffer->commands.last().offset] = pen; return; } + if (buffer->calculateBoundingRect) { if (pen.style() == Qt::NoPen) { buffer->penWidthAdjustment = 0; @@ -427,22 +429,28 @@ void QPaintBufferEngine::penChanged() buffer->penWidthAdjustment = transformedWidth.x() * qreal(0.5); } } +#ifdef QPAINTBUFFER_DEBUG_DRAW + qDebug() << "QPaintBufferEngine: penChanged" << state()->pen; +#endif buffer->addCommand(QPaintBufferPrivate::Cmd_SetPen, pen); } void QPaintBufferEngine::brushChanged() { -#ifdef QPAINTBUFFER_DEBUG_DRAW - qDebug() << "QPaintBufferEngine:" << state()->brush; -#endif const QBrush &brush = state()->brush; if (!buffer->commands.isEmpty() && buffer->commands.last().id == QPaintBufferPrivate::Cmd_SetBrush) { +#ifdef QPAINTBUFFER_DEBUG_DRAW + qDebug() << "QPaintBufferEngine: brushChanged (compressed)" << state()->brush; +#endif buffer->variants[buffer->commands.last().offset] = brush; return; } +#ifdef QPAINTBUFFER_DEBUG_DRAW + qDebug() << "QPaintBufferEngine: brushChanged" << state()->brush; +#endif buffer->addCommand(QPaintBufferPrivate::Cmd_SetBrush, brush); } @@ -488,14 +496,14 @@ void QPaintBufferEngine::transformChanged() if (!buffer->commands.isEmpty() && buffer->commands.last().id == QPaintBufferPrivate::Cmd_SetTransform) { #ifdef QPAINTBUFFER_DEBUG_DRAW - qDebug() << "QPaintBufferEngine: compressing " << state()->matrix; + qDebug() << "QPaintBufferEngine: transformChanged (compressing) " << state()->matrix; #endif buffer->variants[buffer->commands.last().offset] = state()->matrix; return; } #ifdef QPAINTBUFFER_DEBUG_DRAW - qDebug() << "QPaintBufferEngine: " << state()->matrix; + qDebug() << "QPaintBufferEngine: transformChanged:" << state()->matrix; #endif buffer->addCommand(QPaintBufferPrivate::Cmd_SetTransform, state()->matrix); } @@ -514,7 +522,18 @@ void QPaintBufferEngine::draw(const QVectorPath &path) #ifdef QPAINTBUFFER_DEBUG_DRAW qDebug() << "QPaintBufferEngine: draw vpath:" << path.elementCount(); #endif - buffer->addCommand(QPaintBufferPrivate::Cmd_DrawVectorPath, path); + + bool hasBrush = qbrush_style(state()->brush) != Qt::NoBrush; + bool hasPen = qpen_style(state()->pen) != Qt::NoPen + && qbrush_style(qpen_brush(state()->pen)) != Qt::NoBrush; + + if (hasPen || hasBrush) + buffer->addCommand(QPaintBufferPrivate::Cmd_DrawVectorPath, path); +#ifdef QPAINTBUFFER_DEBUG_DRAW + else + qDebug() << " - no pen or brush active, discarded...\n"; +#endif + // if (buffer->calculateBoundingRect) { // QRealRect r = path.controlPointRect(); // buffer->updateBoundingRect(QRectF(r.x1, r.y1, r.x2 - r.x1, r.y2 - r.y1)); @@ -745,15 +764,15 @@ void QPaintBufferEngine::drawEllipse(const QRect &r) void QPaintBufferEngine::drawPath(const QPainterPath &path) { -#ifdef QPAINTBUFFER_DEBUG_DRAW - qDebug() << "QPaintBufferEngine: drawPath: element count:" << path.elementCount(); -#endif - // ### Path -> QVariant - // buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPath, QVariant(path)); +// #ifdef QPAINTBUFFER_DEBUG_DRAW +// qDebug() << "QPaintBufferEngine: drawPath: element count:" << path.elementCount(); +// #endif +// // ### Path -> QVariant +// // buffer->addCommand(QPaintBufferPrivate::Cmd_DrawPath, QVariant(path)); QPaintEngineEx::drawPath(path); - if (buffer->calculateBoundingRect) - buffer->updateBoundingRect(path.boundingRect()); +// if (buffer->calculateBoundingRect) +// buffer->updateBoundingRect(path.boundingRect()); } void QPaintBufferEngine::drawPoints(const QPoint *points, int pointCount) @@ -1424,10 +1443,6 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) QTextItemInt &ti = (*tiCopy)(); QString text(ti.text()); -#ifdef QPAINTBUFFER_DEBUG_DRAW - qDebug() << " -> Cmd_DrawTextItem:" << pos << " " << text << " " << scaleFactor; -#endif - QFont font(ti.font()); font.setUnderline(false); font.setStrikeOut(false); @@ -1439,6 +1454,10 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) justificationWidth = si.width.toReal(); qreal scaleFactor = font.d->dpi/qreal(qt_defaultDpiY()); +#ifdef QPAINTBUFFER_DEBUG_DRAW + qDebug() << " -> Cmd_DrawTextItem:" << pos << " " << text << " " << scaleFactor; +#endif + if (scaleFactor != 1.0) { QFont fnt(font); QFakeDevice fake; diff --git a/src/gui/painting/qpaintbuffer_p.h b/src/gui/painting/qpaintbuffer_p.h index 6a7ac73..adf0564 100644 --- a/src/gui/painting/qpaintbuffer_p.h +++ b/src/gui/painting/qpaintbuffer_p.h @@ -66,6 +66,7 @@ class QPaintBufferPlayback; class Q_GUI_EXPORT QPaintBuffer : public QPaintDevice { + Q_DECLARE_PRIVATE(QPaintBuffer); public: QPaintBuffer(); QPaintBuffer(const QPaintBuffer &other); @@ -311,7 +312,7 @@ public: virtual ~QPainterReplayer() { } void setupTransform(QPainter *painter); - void process(const QPaintBufferCommand &cmd); + virtual void process(const QPaintBufferCommand &cmd); void draw(const QPaintBuffer &buffer, QPainter *painter, int frame); protected: @@ -326,7 +327,7 @@ class Q_GUI_EXPORT QPaintEngineExReplayer : public QPainterReplayer public: QPaintEngineExReplayer() { } - void process(const QPaintBufferCommand &cmd); + virtual void process(const QPaintBufferCommand &cmd); }; class QPaintBufferEnginePrivate; diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index b3d7f08..62b16ab 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -431,6 +431,10 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) // Some engines might decide to optimize for the non-shape hint later on... uint flags = QVectorPath::WindingFill; + + if (path.elementCount() > 2) + flags |= QVectorPath::NonConvexShapeMask; + if (d->stroker.capStyle() == Qt::RoundCap || d->stroker.joinStyle() == Qt::RoundJoin) flags |= QVectorPath::CurvedShapeMask; diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 0cbdfbd..da5b7ac 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -3787,27 +3787,14 @@ void QPainter::setPen(const QPen &pen) if (d->state->pen == pen) return; + d->state->pen = pen; + if (d->extended) { - d->state->pen = pen; d->checkEmulation(); d->extended->penChanged(); return; } - // Do some checks to see if we are the same pen. - Qt::PenStyle currentStyle = d->state->pen.style(); - if (currentStyle == pen.style() && currentStyle != Qt::CustomDashLine) { - if (currentStyle == Qt::NoPen || - (d->state->pen.isSolid() && pen.isSolid() - && d->state->pen.color() == pen.color() - && d->state->pen.widthF() == pen.widthF() - && d->state->pen.capStyle() == pen.capStyle() - && d->state->pen.joinStyle() == pen.joinStyle() - && d->state->pen.isCosmetic() == pen.isCosmetic())) - return; - } - - d->state->pen = pen; d->state->dirtyFlags |= QPaintEngine::DirtyPen; } @@ -3890,14 +3877,6 @@ void QPainter::setBrush(const QBrush &brush) return; } - Qt::BrushStyle currentStyle = d->state->brush.style(); - if (currentStyle == brush.style()) { - if (currentStyle == Qt::NoBrush - || (currentStyle == Qt::SolidPattern - && d->state->brush.color() == brush.color())) - return; - } - d->state->brush = brush; d->state->dirtyFlags |= QPaintEngine::DirtyBrush; } diff --git a/src/gui/painting/qpen.cpp b/src/gui/painting/qpen.cpp index 41efc80..77aa748 100644 --- a/src/gui/painting/qpen.cpp +++ b/src/gui/painting/qpen.cpp @@ -835,16 +835,17 @@ bool QPen::operator==(const QPen &p) const { QPenData *dd = static_cast<QPenData *>(d); QPenData *pdd = static_cast<QPenData *>(p.d); - return (p.d == d) || (p.d->style == d->style - && p.d->capStyle == d->capStyle - && p.d->joinStyle == d->joinStyle - && p.d->width == d->width - && pdd->miterLimit == dd->miterLimit - && (d->style != Qt::CustomDashLine - || (qFuzzyCompare(pdd->dashOffset, dd->dashOffset) && - pdd->dashPattern == dd->dashPattern)) - && p.d->brush == d->brush - && pdd->cosmetic == dd->cosmetic); + return (p.d == d) + || (p.d->style == d->style + && p.d->capStyle == d->capStyle + && p.d->joinStyle == d->joinStyle + && p.d->width == d->width + && pdd->miterLimit == dd->miterLimit + && (d->style != Qt::CustomDashLine + || (qFuzzyCompare(pdd->dashOffset, dd->dashOffset) && + pdd->dashPattern == dd->dashPattern)) + && p.d->brush == d->brush + && pdd->cosmetic == dd->cosmetic); } @@ -983,8 +984,18 @@ QDataStream &operator>>(QDataStream &s, QPen &p) QDebug operator<<(QDebug dbg, const QPen &p) { #ifndef Q_BROKEN_DEBUG_STREAM + const char *PEN_STYLES[] = { + "NoPen", + "SolidLine", + "DashLine", + "DotLine", + "DashDotLine", + "DashDotDotLine", + "CustomDashLine" + }; + dbg.nospace() << "QPen(" << p.width() << ',' << p.brush() - << ',' << int(p.style()) << ',' << int(p.capStyle()) + << ',' << PEN_STYLES[p.style()] << ',' << int(p.capStyle()) << ',' << int(p.joinStyle()) << ',' << p.dashPattern() << ',' << p.dashOffset() << ',' << p.miterLimit() << ')'; diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 4732278..622ceda 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -2215,12 +2215,14 @@ bool qt_scaleForTransform(const QTransform &transform, qreal *scale) { const QTransform::TransformationType type = transform.type(); if (type <= QTransform::TxTranslate) { - *scale = 1; + if (scale) + *scale = 1; return true; } else if (type == QTransform::TxScale) { const qreal xScale = qAbs(transform.m11()); const qreal yScale = qAbs(transform.m22()); - *scale = qMax(xScale, yScale); + if (scale) + *scale = qMax(xScale, yScale); return qFuzzyCompare(xScale, yScale); } @@ -2228,7 +2230,8 @@ bool qt_scaleForTransform(const QTransform &transform, qreal *scale) + transform.m21() * transform.m21(); const qreal yScale = transform.m12() * transform.m12() + transform.m22() * transform.m22(); - *scale = qSqrt(qMax(xScale, yScale)); + if (scale) + *scale = qSqrt(qMax(xScale, yScale)); return type == QTransform::TxRotate && qFuzzyCompare(xScale, yScale); } diff --git a/src/gui/s60framework/qs60mainappui.cpp b/src/gui/s60framework/qs60mainappui.cpp index 3b439a8..4c4c994 100644 --- a/src/gui/s60framework/qs60mainappui.cpp +++ b/src/gui/s60framework/qs60mainappui.cpp @@ -161,8 +161,6 @@ void QS60MainAppUi::HandleResourceChangeL(TInt type) } /*! - * \fn void QS60MainAppUi::HandleWsEventL(const TWsEvent &event, CCoeControl *destination) - * * \brief Handles raw window server events. * * The event type and information is passed in \a wsEvent, while the receiving control is passed in diff --git a/src/gui/statemachine/qguistatemachine.cpp b/src/gui/statemachine/qguistatemachine.cpp index 1de5ffa..4f7806f 100644 --- a/src/gui/statemachine/qguistatemachine.cpp +++ b/src/gui/statemachine/qguistatemachine.cpp @@ -106,8 +106,10 @@ static QEvent *cloneEvent(QEvent *e) return new QEvent(*e); case QEvent::HideToParent: return new QEvent(*e); +#ifndef QT_NO_WHEELEVENT case QEvent::Wheel: return new QWheelEvent(*static_cast<QWheelEvent*>(e)); +#endif //QT_NO_WHEELEVENT case QEvent::WindowTitleChange: return new QEvent(*e); case QEvent::WindowIconChange: @@ -190,8 +192,10 @@ static QEvent *cloneEvent(QEvent *e) return new QInputMethodEvent(*static_cast<QInputMethodEvent*>(e)); case QEvent::AccessibilityPrepare: return new QEvent(*e); +#ifndef QT_NO_TABLETEVENT case QEvent::TabletMove: return new QTabletEvent(*static_cast<QTabletEvent*>(e)); +#endif //QT_NO_TABLETEVENT case QEvent::LocaleChange: return new QEvent(*e); case QEvent::LanguageChange: @@ -200,10 +204,12 @@ static QEvent *cloneEvent(QEvent *e) return new QEvent(*e); case QEvent::Style: return new QEvent(*e); +#ifndef QT_NO_TABLETEVENT case QEvent::TabletPress: return new QTabletEvent(*static_cast<QTabletEvent*>(e)); case QEvent::TabletRelease: return new QTabletEvent(*static_cast<QTabletEvent*>(e)); +#endif //QT_NO_TABLETEVENT case QEvent::OkRequest: return new QEvent(*e); case QEvent::HelpRequest: @@ -238,8 +244,10 @@ static QEvent *cloneEvent(QEvent *e) return new QHelpEvent(*static_cast<QHelpEvent*>(e)); case QEvent::WhatsThis: return new QHelpEvent(*static_cast<QHelpEvent*>(e)); +#ifndef QT_NO_STATUSTIP case QEvent::StatusTip: return new QStatusTipEvent(*static_cast<QStatusTipEvent*>(e)); +#endif //QT_NO_STATUSTIP #ifndef QT_NO_ACTION case QEvent::ActionChanged: case QEvent::ActionAdded: @@ -249,8 +257,10 @@ static QEvent *cloneEvent(QEvent *e) case QEvent::FileOpen: return new QFileOpenEvent(*static_cast<QFileOpenEvent*>(e)); +#ifndef QT_NO_SHORTCUT case QEvent::Shortcut: return new QShortcutEvent(*static_cast<QShortcutEvent*>(e)); +#endif //QT_NO_SHORTCUT case QEvent::ShortcutOverride: return new QKeyEvent(*static_cast<QKeyEvent*>(e)); @@ -263,11 +273,15 @@ static QEvent *cloneEvent(QEvent *e) break; #endif +#ifndef QT_NO_WHATSTHIS case QEvent::WhatsThisClicked: return new QWhatsThisClickedEvent(*static_cast<QWhatsThisClickedEvent*>(e)); +#endif //QT_NO_WHATSTHIS +#ifndef QT_NO_TOOLBAR case QEvent::ToolBarChange: return new QToolBarChangeEvent(*static_cast<QToolBarChangeEvent*>(e)); +#endif //QT_NO_TOOLBAR case QEvent::ApplicationActivate: return new QEvent(*e); @@ -397,9 +411,11 @@ static QEvent *cloneEvent(QEvent *e) case QEvent::DynamicPropertyChange: return new QDynamicPropertyChangeEvent(*static_cast<QDynamicPropertyChangeEvent*>(e)); +#ifndef QT_NO_TABLETEVENT case QEvent::TabletEnterProximity: case QEvent::TabletLeaveProximity: return new QTabletEvent(*static_cast<QTabletEvent*>(e)); +#endif //QT_NO_TABLETEVENT case QEvent::NonClientAreaMouseMove: case QEvent::NonClientAreaMouseButtonPress: diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index ae84442..1c24a03 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -3325,9 +3325,14 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q break; case CE_PushButton: - ParentStyle::drawControl(ce, opt, p, w); - return; - + if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) { + if (rule.hasDrawable() || rule.hasBox() || rule.hasPosition() || rule.hasPalette() || + ((btn->features & QStyleOptionButton::HasMenu) && hasStyleRule(w, PseudoElement_PushButtonMenuIndicator))) { + ParentStyle::drawControl(ce, opt, p, w); + return; + } + } + break; case CE_PushButtonBevel: if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) { QStyleOptionButton btnOpt(*btn); @@ -3370,7 +3375,9 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q if (rule.hasPosition() && rule.position()->textAlignment != 0) { Qt::Alignment textAlignment = rule.position()->textAlignment; QRect textRect = button->rect; - uint tf = Qt::AlignVCenter | Qt::TextShowMnemonic; + uint tf = Qt::TextShowMnemonic; + const uint verticalAlignMask = Qt::AlignVCenter | Qt::AlignTop | Qt::AlignLeft; + tf |= (textAlignment & verticalAlignMask) ? (textAlignment & verticalAlignMask) : Qt::AlignVCenter; if (!styleHint(SH_UnderlineShortcut, button, w)) tf |= Qt::TextHideMnemonic; if (!button->icon.isNull()) { @@ -3599,6 +3606,27 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q } } else if (hasStyleRule(w, PseudoElement_MenuCheckMark) || hasStyleRule(w, PseudoElement_MenuRightArrow)) { QWindowsStyle::drawControl(ce, &mi, p, w); + if (mi.checkType != QStyleOptionMenuItem::NotCheckable && !mi.checked) { + // We have a style defined, but QWindowsStyle won't draw anything if not checked. + // So we mimick what QWindowsStyle would do. + int checkcol = qMax<int>(mi.maxIconWidth, QWindowsStylePrivate::windowsCheckMarkWidth); + QRect vCheckRect = visualRect(opt->direction, mi.rect, QRect(mi.rect.x(), mi.rect.y(), checkcol, mi.rect.height())); + if (mi.state.testFlag(State_Enabled) && mi.state.testFlag(State_Selected)) { + qDrawShadePanel(p, vCheckRect, mi.palette, true, 1, &mi.palette.brush(QPalette::Button)); + } else { + QBrush fill(mi.palette.light().color(), Qt::Dense4Pattern); + qDrawShadePanel(p, vCheckRect, mi.palette, true, 1, &fill); + } + QRenderRule subSubRule = renderRule(w, opt, PseudoElement_MenuCheckMark); + if (subSubRule.hasDrawable()) { + QStyleOptionMenuItem newMi(mi); + newMi.rect = visualRect(opt->direction, mi.rect, QRect(mi.rect.x() + QWindowsStylePrivate::windowsItemFrame, + mi.rect.y() + QWindowsStylePrivate::windowsItemFrame, + checkcol - 2 * QWindowsStylePrivate::windowsItemFrame, + mi.rect.height() - 2 * QWindowsStylePrivate::windowsItemFrame)); + drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, w); + } + } } else { if (rule.hasDrawable() && !subRule.hasDrawable() && !(opt->state & QStyle::State_Selected)) { mi.palette.setColor(QPalette::Window, Qt::transparent); @@ -3668,7 +3696,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q } if (!cb->currentText.isEmpty() && !cb->editable) { drawItemText(p, editRect.adjusted(0, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, cb->palette, - cb->state & State_Enabled, cb->currentText); + cb->state & State_Enabled, cb->currentText, QPalette::Text); } p->restore(); return; @@ -4275,23 +4303,7 @@ void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *op p->fillRect(v2->rect, v2->palette.alternateBase()); subRule.drawRule(p, opt->rect); } else { - QStyleOptionViewItemV2 v2Copy(*v2); - if (v2->showDecorationSelected) { - QRenderRule subRule2 = renderRule(w, opt, PseudoElement_ViewItem); - if (v2->state & QStyle::State_Selected) { - subRule2.configurePalette(&v2Copy.palette, QPalette::NoRole, QPalette::Highlight); - } else if (v2->features & QStyleOptionViewItemV2::Alternate) { - subRule2.configurePalette(&v2Copy.palette, QPalette::NoRole, QPalette::AlternateBase); - } else if (subRule2.hasBackground()) { - p->fillRect(v2->rect, subRule2.background()->brush); - } - } else if (v2->features & QStyleOptionViewItemV2::Alternate) { - quint64 pc = v2->state & QStyle::State_Enabled ? PseudoClass_Enabled : PseudoClass_Disabled; - pc |= PseudoClass_Alternate; - QRenderRule subRule2 = renderRule(w, PseudoElement_ViewItem, pc); - subRule2.configurePalette(&v2Copy.palette, QPalette::NoRole, QPalette::AlternateBase); - } - baseStyle()->drawPrimitive(pe, &v2Copy, p, w); + baseStyle()->drawPrimitive(pe, v2, p, w); } } return; @@ -4356,18 +4368,6 @@ void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *op break; case PE_PanelItemViewItem: - if (!styleHint(SH_ItemView_ShowDecorationSelected, opt, w)) { - rect = subElementRect(QStyle::SE_ItemViewItemText, opt, w) - | subElementRect(QStyle::SE_ItemViewItemDecoration, opt, w) - | subElementRect(QStyle::SE_ItemViewItemCheckIndicator, opt, w); - } - pseudoElement = PseudoElement_ViewItem; - break; - - case PE_PanelItemViewRow: - ParentStyle::drawPrimitive(pe, opt, p, w); - if (!styleHint(SH_ItemView_ShowDecorationSelected, opt, w)) - return; pseudoElement = PseudoElement_ViewItem; break; diff --git a/src/gui/styles/qstylesheetstyle_default.cpp b/src/gui/styles/qstylesheetstyle_default.cpp index 406633e..f79f8e0 100644 --- a/src/gui/styles/qstylesheetstyle_default.cpp +++ b/src/gui/styles/qstylesheetstyle_default.cpp @@ -203,49 +203,6 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const ADD_STYLE_RULE; } - /*QLineEdit[style="QCleanlooksStyle"] { - padding-top: 2px; - padding-bottom: 2px; - }*/ - if (baseStyle()->inherits("QCleanlooksStyle")) - { - SET_ELEMENT_NAME(QLatin1String("QLineEdit")); - ADD_BASIC_SELECTOR; - ADD_SELECTOR; - - - SET_PROPERTY(QLatin1String("padding-top"), PaddingTop); - ADD_VALUE(Value::Identifier, QString::fromLatin1("2px")); - ADD_DECLARATION; - - SET_PROPERTY(QLatin1String("padding-bottom"), PaddingBottom); - ADD_VALUE(Value::Identifier, QString::fromLatin1("2px")); - ADD_DECLARATION; - - ADD_STYLE_RULE; - } - - /*QLineEdit[style="QWindowsXPStyle"], - QLineEdit[style="QWindowsVistaStyle"], - QLineEdit[style="QGtkStyle"] { - padding-top: 1px; - padding-bottom: 1px; - }*/ - if (baseStyle()->inherits("QWindowsXPStyle") || baseStyle()->inherits("QGtkStyle")) - { - SET_ELEMENT_NAME(QLatin1String("QLineEdit")); - - SET_PROPERTY(QLatin1String("padding-top"), PaddingTop); - ADD_VALUE(Value::Identifier, QString::fromLatin1("1px")); - ADD_DECLARATION; - - SET_PROPERTY(QLatin1String("padding-bottom"), PaddingBottom); - ADD_VALUE(Value::Identifier, QString::fromLatin1("1px")); - ADD_DECLARATION; - - ADD_STYLE_RULE; - } - /*QFrame { border: native; }*/ diff --git a/src/gui/styles/qwindowsmobilestyle.cpp b/src/gui/styles/qwindowsmobilestyle.cpp index 7ed187f..86ba947 100644 --- a/src/gui/styles/qwindowsmobilestyle.cpp +++ b/src/gui/styles/qwindowsmobilestyle.cpp @@ -4121,6 +4121,7 @@ void QWindowsMobileStylePrivate::setupWindowsMobileStyle65() void QWindowsMobileStylePrivate::drawTabBarTab(QPainter *painter, const QStyleOptionTab *tab) { +#ifndef QT_NO_TABBAR #ifdef Q_WS_WINCE_WM if (wm65) { tintImagesButton(tab->palette.button().color()); @@ -4207,6 +4208,7 @@ void QWindowsMobileStylePrivate::drawTabBarTab(QPainter *painter, const QStyleOp } } painter->restore(); +#endif //QT_NO_TABBAR } void QWindowsMobileStylePrivate::drawPanelItemViewSelected(QPainter *painter, const QStyleOptionViewItemV4 *option, QRect rect) @@ -4412,7 +4414,7 @@ void QWindowsMobileStylePrivate::drawScrollbarHandleUp(QPainter *p, QStyleOption void QWindowsMobileStylePrivate::drawScrollbarHandleDown(QPainter *p, QStyleOptionSlider *opt, bool completeFrame, bool secondScrollBar) { - +#ifndef QT_NO_SCROLLBAR #ifdef Q_WS_WINCE_WM if (wm65) { tintImagesHigh(opt->palette.highlight().color()); @@ -4469,10 +4471,12 @@ void QWindowsMobileStylePrivate::drawScrollbarHandleDown(QPainter *p, QStyleOpti arrowOpt.rect.adjust(1, 0, 1, 0); q_func()->proxy()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &arrowOpt, p, 0); } +#endif //QT_NO_SCROLLBAR } void QWindowsMobileStylePrivate::drawScrollbarGroove(QPainter *p,const QStyleOptionSlider *opt) { +#ifndef QT_NO_SCROLLBAR #ifdef Q_OS_WINCE_WM if (wm65) { p->fillRect(opt->rect, QColor(231, 231, 231)); @@ -4498,6 +4502,7 @@ void QWindowsMobileStylePrivate::drawScrollbarGroove(QPainter *p,const QStyleOpt fill = opt->palette.light(); } p->fillRect(opt->rect, fill); +#endif //QT_NO_SCROLLBAR } QWindowsMobileStyle::QWindowsMobileStyle(QWindowsMobileStylePrivate &dd) : QWindowsStyle(dd) { @@ -6325,16 +6330,20 @@ QSize QWindowsMobileStyle::sizeFromContents(ContentsType type, const QStyleOptio switch (type) { case CT_PushButton: if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) { - newSize = QWindowsStyle::sizeFromContents(type, option, size, widget); + newSize = QCommonStyle::sizeFromContents(type, option, size, widget); int w = newSize.width(), h = newSize.height(); int defwidth = 0; if (button->features & QStyleOptionButton::AutoDefaultButton) defwidth = 2 * proxy()->pixelMetric(PM_ButtonDefaultIndicator, button, widget); - if (w < 75 + defwidth && button->icon.isNull()) - w = 75 + defwidth; - if (h < 23 + defwidth) - h = 23 + defwidth; + + int minwidth = int(QStyleHelper::dpiScaled(55.0f)); + int minheight = int(QStyleHelper::dpiScaled(19.0f)); + + if (w < minwidth + defwidth && button->icon.isNull()) + w = minwidth + defwidth; + if (h < minheight + defwidth) + h = minheight + defwidth; newSize = QSize(w + 4, h + 4); } break; diff --git a/src/gui/styles/qwindowsmobilestyle_p.h b/src/gui/styles/qwindowsmobilestyle_p.h index 1e8c7ff..139a4ab 100644 --- a/src/gui/styles/qwindowsmobilestyle_p.h +++ b/src/gui/styles/qwindowsmobilestyle_p.h @@ -60,6 +60,10 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_STYLE_WINDOWSMOBILE +class QStyleOptionTab; +class QStyleOptionSlider; +class QStyleOptionViewItemV4; + class QWindowsMobileStylePrivate : public QWindowsStylePrivate { Q_DECLARE_PUBLIC(QWindowsMobileStyle) diff --git a/src/gui/styles/qwindowsstyle.cpp b/src/gui/styles/qwindowsstyle.cpp index 5cf738e..f894b82 100644 --- a/src/gui/styles/qwindowsstyle.cpp +++ b/src/gui/styles/qwindowsstyle.cpp @@ -115,14 +115,6 @@ QT_BEGIN_INCLUDE_NAMESPACE #include <limits.h> QT_END_INCLUDE_NAMESPACE -static const int windowsItemFrame = 2; // menu item frame width -static const int windowsSepHeight = 9; // separator item height -static const int windowsItemHMargin = 3; // menu item hor text margin -static const int windowsItemVMargin = 2; // menu item ver text margin -static const int windowsArrowHMargin = 6; // arrow horizontal margin -static const int windowsRightBorder = 15; // right border on windows -static const int windowsCheckMarkWidth = 12; // checkmarks width on windows - enum QSliderDirection { SlUp, SlDown, SlLeft, SlRight }; /* @@ -1847,7 +1839,7 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai bool act = menuitem->state & State_Selected; // windows always has a check column, regardless whether we have an icon or not - int checkcol = qMax(menuitem->maxIconWidth, windowsCheckMarkWidth); + int checkcol = qMax<int>(menuitem->maxIconWidth, QWindowsStylePrivate::windowsCheckMarkWidth); QBrush fill = menuitem->palette.brush(act ? QPalette::Highlight : QPalette::Button); p->fillRect(menuitem->rect.adjusted(0, 0, -1, 0), fill); @@ -1903,8 +1895,10 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai newMi.state |= State_Enabled; if (act) newMi.state |= State_On; - newMi.rect = visualRect(opt->direction, menuitem->rect, QRect(menuitem->rect.x() + windowsItemFrame, menuitem->rect.y() + windowsItemFrame, - checkcol - 2 * windowsItemFrame, menuitem->rect.height() - 2*windowsItemFrame)); + newMi.rect = visualRect(opt->direction, menuitem->rect, QRect(menuitem->rect.x() + QWindowsStylePrivate::windowsItemFrame, + menuitem->rect.y() + QWindowsStylePrivate::windowsItemFrame, + checkcol - 2 * QWindowsStylePrivate::windowsItemFrame, + menuitem->rect.height() - 2 * QWindowsStylePrivate::windowsItemFrame)); proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, widget); } p->setPen(act ? menuitem->palette.highlightedText().color() : menuitem->palette.buttonText().color()); @@ -1915,9 +1909,10 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai p->setPen(discol); } - int xm = windowsItemFrame + checkcol + windowsItemHMargin; + int xm = QWindowsStylePrivate::windowsItemFrame + checkcol + QWindowsStylePrivate::windowsItemHMargin; int xpos = menuitem->rect.x() + xm; - QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin); + QRect textRect(xpos, y + QWindowsStylePrivate::windowsItemVMargin, + w - xm - QWindowsStylePrivate::windowsRightBorder - tab + 1, h - 2 * QWindowsStylePrivate::windowsItemVMargin); QRect vTextRect = visualRect(opt->direction, menuitem->rect, textRect); QString s = menuitem->text; if (!s.isEmpty()) { // draw text @@ -1951,10 +1946,10 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai p->restore(); } if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow - int dim = (h - 2 * windowsItemFrame) / 2; + int dim = (h - 2 * QWindowsStylePrivate::windowsItemFrame) / 2; PrimitiveElement arrow; arrow = (opt->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight; - xpos = x + w - windowsArrowHMargin - windowsItemFrame - dim; + xpos = x + w - QWindowsStylePrivate::windowsArrowHMargin - QWindowsStylePrivate::windowsItemFrame - dim; QRect vSubMenuRect = visualRect(opt->direction, menuitem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim)); QStyleOptionMenuItem newMI = *menuitem; newMI.rect = vSubMenuRect; @@ -2994,6 +2989,7 @@ void QWindowsStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComp #ifndef QT_NO_COMBOBOX case CC_ComboBox: if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) { + p->save(); QBrush editBrush = cmb->palette.brush(QPalette::Base); if ((cmb->subControls & SC_ComboBoxFrame)) { if (cmb->frame) { @@ -3063,6 +3059,7 @@ void QWindowsStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComp proxy()->drawPrimitive(PE_FrameFocusRect, &focus, p, widget); } } + p->restore(); } break; #endif // QT_NO_COMBOBOX @@ -3191,7 +3188,7 @@ QSize QWindowsStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget); if (mi->menuItemType == QStyleOptionMenuItem::Separator) { - sz = QSize(10, windowsSepHeight); + sz = QSize(10, QWindowsStylePrivate::windowsSepHeight); } else if (mi->icon.isNull()) { sz.setHeight(sz.height() - 2); @@ -3202,14 +3199,14 @@ QSize QWindowsStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt, widget); sz.setHeight(qMax(sz.height(), mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() - + 2 * windowsItemFrame)); + + 2 * QWindowsStylePrivate::windowsItemFrame)); } int maxpmw = mi->maxIconWidth; int tabSpacing = 20; if (mi->text.contains(QLatin1Char('\t'))) w += tabSpacing; else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu) - w += 2 * windowsArrowHMargin; + w += 2 * QWindowsStylePrivate::windowsArrowHMargin; else if (mi->menuItemType == QStyleOptionMenuItem::DefaultItem) { // adjust the font and add the difference in size. // it would be better if the font could be adjusted in the initStyleOption qmenu func!! @@ -3220,9 +3217,9 @@ QSize QWindowsStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, w += fmBold.width(mi->text) - fm.width(mi->text); } - int checkcol = qMax(maxpmw, windowsCheckMarkWidth); // Windows always shows a check column + int checkcol = qMax<int>(maxpmw, QWindowsStylePrivate::windowsCheckMarkWidth); // Windows always shows a check column w += checkcol; - w += windowsRightBorder + 10; + w += QWindowsStylePrivate::windowsRightBorder + 10; sz.setWidth(w); } break; @@ -3230,7 +3227,7 @@ QSize QWindowsStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, #ifndef QT_NO_MENUBAR case CT_MenuBarItem: if (!sz.isEmpty()) - sz += QSize(windowsItemHMargin * 4, windowsItemVMargin * 2); + sz += QSize(QWindowsStylePrivate::windowsItemHMargin * 4, QWindowsStylePrivate::windowsItemVMargin * 2); break; #endif // Otherwise, fall through diff --git a/src/gui/styles/qwindowsstyle_p.h b/src/gui/styles/qwindowsstyle_p.h index fb84dce..d81c82b 100644 --- a/src/gui/styles/qwindowsstyle_p.h +++ b/src/gui/styles/qwindowsstyle_p.h @@ -87,7 +87,17 @@ public: QColor activeGradientCaptionColor; QColor inactiveCaptionColor; QColor inactiveGradientCaptionColor; + + enum { + windowsItemFrame = 2, // menu item frame width + windowsSepHeight = 9, // separator item height + windowsItemHMargin = 3, // menu item hor text margin + windowsItemVMargin = 2, // menu item ver text margin + windowsArrowHMargin = 6, // arrow horizontal margin + windowsRightBorder = 15, // right border on windows + windowsCheckMarkWidth = 12 // checkmarks width on windows }; +}; QT_END_NAMESPACE diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index 6db86bd..93b9fc6 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -1129,19 +1129,22 @@ static bool setFontWeightFromValue(const Value &value, QFont *font) static bool setFontFamilyFromValues(const QVector<Value> &values, QFont *font, int start = 0) { QString family; + bool shouldAddSpace = false; for (int i = start; i < values.count(); ++i) { const Value &v = values.at(i); if (v.type == Value::TermOperatorComma) { family += QLatin1Char(','); + shouldAddSpace = false; continue; } const QString str = v.variant.toString(); if (str.isEmpty()) break; + if (shouldAddSpace) + family += QLatin1Char(' '); family += str; - family += QLatin1Char(' '); + shouldAddSpace = true; } - family = family.simplified(); if (family.isEmpty()) return false; font->setFamily(family); diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 1ceb28b..e8a0068 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -533,7 +533,13 @@ static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { // Vietnamese, { 0, 127 }, // same as latin1 // Other, - { 126, 127 } + { 126, 127 }, + // Ogham, + { 78, 127 }, + // Runic, + { 79, 127 }, + // Nko, + { 14, 127 }, }; #define SimplifiedChineseCsbBit 18 @@ -873,7 +879,8 @@ static const int scriptForWritingSystem[] = { QUnicodeTables::Common, // Braille QUnicodeTables::Common, // Symbol QUnicodeTables::Ogham, // Ogham - QUnicodeTables::Runic // Runic + QUnicodeTables::Runic, // Runic + QUnicodeTables::Nko // Nko }; @@ -881,12 +888,12 @@ static const int scriptForWritingSystem[] = { static inline bool requiresOpenType(int writingSystem) { return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala) - || writingSystem == QFontDatabase::Khmer); + || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko); } static inline bool scriptRequiresOpenType(int script) { return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) - || script == QUnicodeTables::Khmer); + || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); } #endif @@ -1558,6 +1565,7 @@ QFontDatabase::QFontDatabase() \value Other (the same as Symbol) \value Ogham \value Runic + \value Nko \omitvalue WritingSystemsCount */ @@ -2234,6 +2242,9 @@ QString QFontDatabase::writingSystemName(WritingSystem writingSystem) case Runic: name = QT_TRANSLATE_NOOP("QFontDatabase", "Runic"); break; + case Nko: + name = QT_TRANSLATE_NOOP("QFontDatabase", "N'Ko"); + break; default: Q_ASSERT_X(false, "QFontDatabase::writingSystemName", "invalid 'writingSystem' parameter"); break; @@ -2447,6 +2458,12 @@ QString QFontDatabase::writingSystemSample(WritingSystem writingSystem) sample += QChar(0x16a2); sample += QChar(0x16a3); break; + case Nko: + sample += QChar(0x7ca); + sample += QChar(0x7cb); + sample += QChar(0x7cc); + sample += QChar(0x7cd); + break; default: break; } diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index e6dcfc9..37b5860 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -108,6 +108,7 @@ public: Ogham, Runic, + Nko, WritingSystemsCount }; diff --git a/src/gui/text/qfontdatabase_x11.cpp b/src/gui/text/qfontdatabase_x11.cpp index f184811..dd575f9 100644 --- a/src/gui/text/qfontdatabase_x11.cpp +++ b/src/gui/text/qfontdatabase_x11.cpp @@ -155,187 +155,187 @@ static const char writingSystems_for_xlfd_encoding[sizeof(xlfd_encoding)][QFontD { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso8859-2 { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso8859-3 { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso8859-4 { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso8859-9 { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso8859-10 { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso8859-13 { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso8859-14 { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso8859-15 { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // hp-roman8 { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso8859-5 { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // *-cp1251 { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // koi8-ru { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // koi8-u { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // koi8-r { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso8859-7 { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso8859-8 { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // gb18030-0 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0 }, + 0, 0 }, // gb18030.2000-0 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0 }, + 0, 0 }, // gbk-0 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0 }, + 0, 0 }, // gb2312.*-0 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0 }, + 0, 0 }, // jisx0201*-0 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, - 0 }, + 0, 0 }, // jisx0208*-0 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, - 0 }, + 0, 0 }, // ksc5601*-* { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0 }, + 0, 0 }, // big5hkscs-0 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0 }, + 0, 0 }, // hkscs-1 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0 }, + 0, 0 }, // big5*-* { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0 }, + 0, 0 }, // tscii-* { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // tis620*-* { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso8859-11 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // mulelao-1 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // ethiopic-unicode { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0 }, + 0, 0 }, // iso10646-1 { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, - 0 }, + 0, 0 }, // unicode-* { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, - 0 }, + 0, 0 }, // *-symbol { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1 }, + 1, 0 }, // *-fontspecific { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1 }, + 1, 0 }, // fontspecific-* { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1 } + 1, 0 } }; @@ -835,7 +835,8 @@ static const char *specialLanguages[] = { "ko", // Hangul "", // Ogham "", // Runic - "km" // Khmer + "km", // Khmer + "" // N'Ko }; enum { SpecialLanguageCount = sizeof(specialLanguages) / sizeof(const char *) }; @@ -866,7 +867,8 @@ static const ushort specialChars[] = { 0, // Hangul 0x1681, // Ogham 0x16a0, // Runic - 0 // Khmer + 0, // Khmer + 0x7ca // N'Ko }; enum { SpecialCharCount = sizeof(specialChars) / sizeof(ushort) }; @@ -905,7 +907,8 @@ static const char *languageForWritingSystem[] = { "vi", // Vietnamese 0, // Symbol 0, // Ogham - 0 // Runic + 0, // Runic + 0 // N'Ko }; enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) }; @@ -944,7 +947,8 @@ static const ushort sampleCharForWritingSystem[] = { 0, // Vietnamese 0, // Symbol 0x1681, // Ogham - 0x16a0 // Runic + 0x16a0, // Runic + 0x7ca // N'Ko }; enum { SampleCharCount = sizeof(sampleCharForWritingSystem) / sizeof(ushort) }; @@ -984,7 +988,8 @@ static const char *openType[] = { 0, // Vietnamese 0, // Symbol 0, // Ogham - 0 // Runic + 0, // Runic + "nko " // N'Ko }; enum { OpenTypeCount = sizeof(openType) / sizeof(const char *) }; @@ -1472,7 +1477,7 @@ void qt_addPatternProps(FcPattern *pattern, int screen, int script, const QFontD !(request.styleStrategy & QFont::NoAntialias)); } - if (script != QUnicodeTables::Common) { + if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') { Q_ASSERT(script < QUnicodeTables::ScriptCount); FcLangSet *ls = FcLangSetCreate(); FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]); @@ -1615,7 +1620,7 @@ static QFontEngine *tryPatternLoad(FcPattern *p, int screen, goto done; if (!FcCharSetHasChar(cs, specialChars[script])) goto done; - } else { + } else if (*specialLanguages[script] != '\0'){ FcLangSet *langSet = 0; if (FcPatternGetLangSet(match, FC_LANG, 0, &langSet) != FcResultMatch) goto done; diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index 9497b6f..2bfe33c 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -911,7 +911,7 @@ void QTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *conte break; case QEvent::MouseButtonPress: { QMouseEvent *ev = static_cast<QMouseEvent *>(e); - d->mousePressEvent(ev->button(), matrix.map(ev->pos()), ev->modifiers(), + d->mousePressEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(), ev->globalPos()); break; } case QEvent::MouseMove: { @@ -979,7 +979,7 @@ void QTextControl::processEvent(QEvent *e, const QMatrix &matrix, QWidget *conte #ifndef QT_NO_GRAPHICSVIEW case QEvent::GraphicsSceneMousePress: { QGraphicsSceneMouseEvent *ev = static_cast<QGraphicsSceneMouseEvent *>(e); - d->mousePressEvent(ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(), + d->mousePressEvent(ev, ev->button(), matrix.map(ev->pos()), ev->modifiers(), ev->buttons(), ev->screenPos()); break; } case QEvent::GraphicsSceneMouseMove: { @@ -1296,7 +1296,9 @@ QVariant QTextControl::loadResource(int type, const QUrl &name) void QTextControlPrivate::_q_updateBlock(const QTextBlock &block) { Q_Q(QTextControl); - emit q->updateRequest(q->blockBoundingRect(block)); + QRectF br = q->blockBoundingRect(block); + br.setRight(qreal(INT_MAX)); // the block might have shrunk + emit q->updateRequest(br); } QRectF QTextControlPrivate::rectForPosition(int position) const @@ -1465,7 +1467,7 @@ QRectF QTextControl::selectionRect() const return selectionRect(d->cursor); } -void QTextControlPrivate::mousePressEvent(Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers, +void QTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint &globalPos) { Q_Q(QTextControl); @@ -1479,11 +1481,11 @@ void QTextControlPrivate::mousePressEvent(Qt::MouseButton button, const QPointF cursor.clearSelection(); } } - if (!(button & Qt::LeftButton)) - return; - - if (!((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) - return; + if (!(button & Qt::LeftButton) || + !((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) { + e->ignore(); + return; + } cursorIsFocusIndicator = false; const QTextCursor oldSelection = cursor; @@ -1507,8 +1509,10 @@ void QTextControlPrivate::mousePressEvent(Qt::MouseButton button, const QPointF trippleClickTimer.stop(); } else { int cursorPos = q->hitTest(pos, Qt::FuzzyHit); - if (cursorPos == -1) + if (cursorPos == -1) { + e->ignore(); return; + } #if !defined(QT_NO_IM) QTextLayout *layout = cursor.block().layout(); @@ -1519,8 +1523,10 @@ void QTextControlPrivate::mousePressEvent(Qt::MouseButton button, const QPointF button, buttons, modifiers); ctx->mouseHandler(cursorPos - cursor.position(), &ev); } - if (!layout->preeditAreaText().isEmpty()) + if (!layout->preeditAreaText().isEmpty()) { + e->ignore(); return; + } } #endif if (modifiers == Qt::ShiftModifier) { diff --git a/src/gui/text/qtextcontrol_p_p.h b/src/gui/text/qtextcontrol_p_p.h index ca9db9f..66459f6 100644 --- a/src/gui/text/qtextcontrol_p_p.h +++ b/src/gui/text/qtextcontrol_p_p.h @@ -131,10 +131,10 @@ public: QString anchorForCursor(const QTextCursor &anchor) const; void keyPressEvent(QKeyEvent *e); - void mousePressEvent(Qt::MouseButton button, const QPointF &pos, + void mousePressEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos, Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, - const QPoint &globalPos = QPoint()); + const QPoint &globalPos); void mouseMoveEvent(Qt::MouseButtons buttons, const QPointF &pos); void mouseReleaseEvent(Qt::MouseButton button, const QPointF &pos); void mouseDoubleClickEvent(QEvent *e, Qt::MouseButton button, const QPointF &pos); diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp index 85b539f..fd84949 100644 --- a/src/gui/util/qdesktopservices.cpp +++ b/src/gui/util/qdesktopservices.cpp @@ -293,8 +293,6 @@ void QDesktopServices::unsetUrlHandler(const QString &scheme) have desktop concept, DesktopLocation returns same path as DocumentsLocation. Rest of the standard locations point to folder on same drive with executable, except that if executable is in ROM the folder from C drive is returned. - - \endcode */ /*! diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index 1879db4..bd1d8ba 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -1111,6 +1111,32 @@ void QComboBoxPrivate::updateLineEditGeometry() lineEdit->setGeometry(editRect); } +Qt::MatchFlags QComboBoxPrivate::matchFlags() const +{ + // Base how duplicates are determined on the autocompletion case sensitivity + Qt::MatchFlags flags = Qt::MatchFixedString; +#ifndef QT_NO_COMPLETER + if (!lineEdit->completer() || lineEdit->completer()->caseSensitivity() == Qt::CaseSensitive) +#endif + flags |= Qt::MatchCaseSensitive; + return flags; +} + + +void QComboBoxPrivate::_q_editingFinished() +{ + Q_Q(QComboBox); + if (lineEdit && !lineEdit->text().isEmpty()) { + //here we just check if the current item was entered + const int index = q_func()->findText(lineEdit->text(), matchFlags()); + if (index != -1 && itemText(currentIndex) != lineEdit->text()) { + q->setCurrentIndex(index); + emitActivated(currentIndex); + } + } + +} + void QComboBoxPrivate::_q_returnPressed() { Q_Q(QComboBox); @@ -1123,13 +1149,7 @@ void QComboBoxPrivate::_q_returnPressed() // check for duplicates (if not enabled) and quit int index = -1; if (!duplicatesEnabled) { - // Base how duplicates are determined on the autocompletion case sensitivity - Qt::MatchFlags flags = Qt::MatchFixedString; -#ifndef QT_NO_COMPLETER - if (!lineEdit->completer() || lineEdit->completer()->caseSensitivity() == Qt::CaseSensitive) -#endif - flags |= Qt::MatchCaseSensitive; - index = q->findText(text, flags); + index = q->findText(text, matchFlags()); if (index != -1) { q->setCurrentIndex(index); emitActivated(currentIndex); @@ -1664,6 +1684,7 @@ void QComboBox::setLineEdit(QLineEdit *edit) if (d->lineEdit->parent() != this) d->lineEdit->setParent(this); connect(d->lineEdit, SIGNAL(returnPressed()), this, SLOT(_q_returnPressed())); + connect(d->lineEdit, SIGNAL(editingFinished()), this, SLOT(_q_editingFinished())); connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(editTextChanged(QString))); #ifdef QT3_SUPPORT connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged(QString))); @@ -1960,7 +1981,7 @@ void QComboBoxPrivate::setCurrentIndex(const QModelIndex &mi) if (lineEdit) { QString newText = q->itemText(currentIndex.row()); if (lineEdit->text() != newText) - lineEdit->setText(q->itemText(currentIndex.row())); + lineEdit->setText(newText); updateLineEditGeometry(); } if (indexChanged) { diff --git a/src/gui/widgets/qcombobox.h b/src/gui/widgets/qcombobox.h index 0652594..5d5ea21 100644 --- a/src/gui/widgets/qcombobox.h +++ b/src/gui/widgets/qcombobox.h @@ -304,6 +304,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_itemSelected(const QModelIndex &item)) Q_PRIVATE_SLOT(d_func(), void _q_emitHighlighted(const QModelIndex &)) Q_PRIVATE_SLOT(d_func(), void _q_emitCurrentIndexChanged(const QModelIndex &index)) + Q_PRIVATE_SLOT(d_func(), void _q_editingFinished()) Q_PRIVATE_SLOT(d_func(), void _q_returnPressed()) Q_PRIVATE_SLOT(d_func(), void _q_resetButton()) Q_PRIVATE_SLOT(d_func(), void _q_dataChanged(const QModelIndex &, const QModelIndex &)) diff --git a/src/gui/widgets/qcombobox_p.h b/src/gui/widgets/qcombobox_p.h index fe42c47..f6ba57c 100644 --- a/src/gui/widgets/qcombobox_p.h +++ b/src/gui/widgets/qcombobox_p.h @@ -342,6 +342,8 @@ public: void init(); QComboBoxPrivateContainer* viewContainer(); void updateLineEditGeometry(); + Qt::MatchFlags matchFlags() const; + void _q_editingFinished(); void _q_returnPressed(); void _q_complete(); void _q_itemSelected(const QModelIndex &item); diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 0fc94c9..2914164 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -1511,6 +1511,18 @@ void QLineControl::processKeyEvent(QKeyEvent* event) } #endif // QT_NO_COMPLETER + if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { + if (hasAcceptableInput() || fixup()) { + emit accepted(); + emit editingFinished(); + } + if (inlineCompletionAccepted) + event->accept(); + else + event->ignore(); + return; + } + if (echoMode() == QLineEdit::PasswordEchoOnEdit && !passwordEchoEditing() && !isReadOnly() @@ -1531,17 +1543,6 @@ void QLineControl::processKeyEvent(QKeyEvent* event) clear(); } - if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { - if (hasAcceptableInput() || fixup()) { - emit accepted(); - emit editingFinished(); - } - if (inlineCompletionAccepted) - event->accept(); - else - event->ignore(); - return; - } bool unknown = false; if (false) { diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index 1b5d1cd..cc39b7f 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -273,7 +273,7 @@ void QMenuPrivate::updateActionRects() const for (int i = 0; i < actions.count(); ++i) { QAction *action = actions.at(i); - if (action->isSeparator() || !action->isVisible() || widgetItems.at(i)) + if (action->isSeparator() || !action->isVisible() || widgetItems.contains(action)) continue; //..and some members hasCheckableItems |= action->isCheckable(); @@ -301,7 +301,7 @@ void QMenuPrivate::updateActionRects() const const QFontMetrics &fm = opt.fontMetrics; QSize sz; - if (QWidget *w = widgetItems.at(i)) { + if (QWidget *w = widgetItems.value(action)) { sz = w->sizeHint().expandedTo(w->minimumSize()).expandedTo(w->minimumSizeHint()).boundedTo(w->maximumSize()); } else { //calc what I think the size is.. @@ -370,7 +370,7 @@ void QMenuPrivate::updateActionRects() const rect.setWidth(max_column_width); //uniform width //we need to update the widgets geometry - if (QWidget *widget = widgetItems.at(i)) { + if (QWidget *widget = widgetItems.value(actions.at(i))) { widget->setGeometry(rect); widget->setVisible(actions.at(i)->isVisible()); } @@ -583,8 +583,7 @@ void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason q->update(actionRect(action)); if (reason == SelectedFromKeyboard) { - const int actionIndex = actions.indexOf(action); - QWidget *widget = widgetItems.at(actionIndex); + QWidget *widget = widgetItems.value(action); if (widget) { if (widget->focusPolicy() != Qt::NoFocus) widget->setFocus(Qt::TabFocusReason); @@ -800,7 +799,7 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc current.moveTop(current.top() + delta); //we need to update the widgets geometry - if (QWidget *w = widgetItems.at(i)) + if (QWidget *w = widgetItems.value(actions.at(i))) w->setGeometry(current); } } @@ -1392,11 +1391,12 @@ QMenu::QMenu(QMenuPrivate &dd, QWidget *parent) QMenu::~QMenu() { Q_D(QMenu); - for (int i = 0; i < d->widgetItems.count(); ++i) { - if (QWidget *widget = d->widgetItems.at(i)) { - QWidgetAction *action = static_cast<QWidgetAction *>(d->actions.at(i)); + QHash<QAction *, QWidget *>::iterator it = d->widgetItems.begin(); + for (; it != d->widgetItems.end(); ++it) { + if (QWidget *widget = it.value()) { + QWidgetAction *action = static_cast<QWidgetAction *>(it.key()); action->releaseWidget(widget); - d->widgetItems[i] = 0; + *it = 0; } } @@ -1878,9 +1878,11 @@ void QMenu::popup(const QPoint &p, QAction *atAction) if(snapToMouse) //position flowing left from the mouse pos.setX(mouse.x()-size.width()); +#ifndef QT_NO_MENUBAR //if in a menubar, it should be right-aligned if (qobject_cast<QMenuBar*>(d->causedPopup.widget)) pos.rx() -= size.width(); +#endif //QT_NO_MENUBAR if (pos.x() < screen.left()+desktopFrame) pos.setX(qMax(p.x(), screen.left()+desktopFrame)); @@ -2151,7 +2153,7 @@ void QMenu::paintEvent(QPaintEvent *e) QAction *action = d->actions.at(i); QRect adjustedActionRect = d->actionRects.at(i); if (!e->rect().intersects(adjustedActionRect) - || d->widgetItems.at(i)) + || d->widgetItems.value(action)) continue; //set the clip region to be extra safe (and adjust for the scrollers) QRegion adjustedActionReg(adjustedActionRect); @@ -2862,25 +2864,20 @@ void QMenu::actionEvent(QActionEvent *e) connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered())); connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered())); } - QWidget *widget = 0; - if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) - widget = wa->requestWidget(this); - - int index = d->actions.indexOf(e->action()); - Q_ASSERT(index != -1); - d->widgetItems.insert(index, widget); - + if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) { + QWidget *widget = wa->requestWidget(this); + if (widget) + d->widgetItems.insert(wa, widget); + } } else if (e->type() == QEvent::ActionRemoved) { e->action()->disconnect(this); if (e->action() == d->currentAction) d->currentAction = 0; - int index = d->actions.indexOf(e->before()) + 1; if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) { - if (QWidget *widget = d->widgetItems.at(index)) + if (QWidget *widget = d->widgetItems.value(wa)) wa->releaseWidget(widget); } - Q_ASSERT(index != -1); - d->widgetItems.removeAt(index); + d->widgetItems.remove(e->action()); } #ifdef Q_WS_MAC diff --git a/src/gui/widgets/qmenu_mac.mm b/src/gui/widgets/qmenu_mac.mm index b238faf..9510cc6 100644 --- a/src/gui/widgets/qmenu_mac.mm +++ b/src/gui/widgets/qmenu_mac.mm @@ -1191,7 +1191,7 @@ QMenuPrivate::QMacMenuPrivate::addAction(QMacMenuAction *action, QMacMenuAction #endif } - QWidget *widget = qmenu ? qmenu->widgetItems.value(qmenu->actions.indexOf(action->action)) : 0; + QWidget *widget = qmenu ? qmenu->widgetItems.value(action->action) : 0; if (widget) { #ifndef QT_MAC_USE_COCOA ChangeMenuAttributes(action->menu, kMenuAttrDoNotCacheImage, 0); diff --git a/src/gui/widgets/qmenu_p.h b/src/gui/widgets/qmenu_p.h index 9348f7b..a5bde7c 100644 --- a/src/gui/widgets/qmenu_p.h +++ b/src/gui/widgets/qmenu_p.h @@ -190,7 +190,7 @@ public: QRect actionRect(QAction *) const; mutable QVector<QRect> actionRects; - mutable QWidgetList widgetItems; + mutable QHash<QAction *, QWidget *> widgetItems; void updateActionRects() const; QRect popupGeometry(const QWidget *widget) const; QRect popupGeometry(int screen = -1) const; diff --git a/src/gui/widgets/qwidgetanimator.cpp b/src/gui/widgets/qwidgetanimator.cpp index bdd3c75..13ee346 100644 --- a/src/gui/widgets/qwidgetanimator.cpp +++ b/src/gui/widgets/qwidgetanimator.cpp @@ -88,8 +88,6 @@ void QWidgetAnimator::animate(QWidget *widget, const QRect &_final_geometry, boo const QRect final_geometry = _final_geometry.isValid() || widget->isWindow() ? _final_geometry : QRect(QPoint(-500 - widget->width(), -500 - widget->height()), widget->size()); - if (r == final_geometry) - return; //the widget is already where it should be #ifndef QT_NO_ANIMATION AnimationMap::const_iterator it = m_animation_map.constFind(widget); if (it != m_animation_map.constEnd() && (*it)->endValue().toRect() == final_geometry) @@ -116,9 +114,4 @@ bool QWidgetAnimator::animating() const return !m_animation_map.isEmpty(); } -bool QWidgetAnimator::animating(QWidget *widget) const -{ - return m_animation_map.contains(widget); -} - QT_END_NAMESPACE diff --git a/src/gui/widgets/qwidgetanimator_p.h b/src/gui/widgets/qwidgetanimator_p.h index 68d9344..095380f 100644 --- a/src/gui/widgets/qwidgetanimator_p.h +++ b/src/gui/widgets/qwidgetanimator_p.h @@ -70,7 +70,6 @@ public: QWidgetAnimator(QMainWindowLayout *layout); void animate(QWidget *widget, const QRect &final_geometry, bool animate); bool animating() const; - bool animating(QWidget *widget) const; void abort(QWidget *widget); diff --git a/src/network/socket/qlocalsocket_win.cpp b/src/network/socket/qlocalsocket_win.cpp index 8a745ab..d812d88 100644 --- a/src/network/socket/qlocalsocket_win.cpp +++ b/src/network/socket/qlocalsocket_win.cpp @@ -363,7 +363,8 @@ bool QLocalSocket::canReadLine() const Q_D(const QLocalSocket); if (state() != ConnectedState) return false; - return (d->readBuffer.indexOf('\n') != -1 || QIODevice::canReadLine()); + return (QIODevice::canReadLine() + || d->readBuffer.indexOf('\n', d->actualReadBufferSize) != -1); } void QLocalSocket::close() diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 40a6241..8a8f483 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -169,14 +169,14 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) source.clear(); source.append(qShaderSnippets[MainVertexShader]); source.append(qShaderSnippets[PositionOnlyVertexShader]); - vertexShader = new QGLShader(QGLShader::VertexShader, context, this); - vertexShader->compile(source); + vertexShader = new QGLShader(QGLShader::Vertex, context, this); + vertexShader->compileSourceCode(source); source.clear(); source.append(qShaderSnippets[MainFragmentShader]); source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]); - fragShader = new QGLShader(QGLShader::FragmentShader, context, this); - fragShader->compile(source); + fragShader = new QGLShader(QGLShader::Fragment, context, this); + fragShader->compileSourceCode(source); simpleShaderProg = new QGLShaderProgram(context, this); simpleShaderProg->addShader(vertexShader); @@ -192,14 +192,14 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) source.clear(); source.append(qShaderSnippets[MainWithTexCoordsVertexShader]); source.append(qShaderSnippets[UntransformedPositionVertexShader]); - vertexShader = new QGLShader(QGLShader::VertexShader, context, this); - vertexShader->compile(source); + vertexShader = new QGLShader(QGLShader::Vertex, context, this); + vertexShader->compileSourceCode(source); source.clear(); source.append(qShaderSnippets[MainFragmentShader]); source.append(qShaderSnippets[ImageSrcFragmentShader]); - fragShader = new QGLShader(QGLShader::FragmentShader, context, this); - fragShader->compile(source); + fragShader = new QGLShader(QGLShader::Fragment, context, this); + fragShader->compileSourceCode(source); blitShaderProg = new QGLShaderProgram(context, this); blitShaderProg->addShader(vertexShader); @@ -243,14 +243,14 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS source.append(qShaderSnippets[prog.compositionFragShader]); if (prog.maskFragShader) source.append(qShaderSnippets[prog.maskFragShader]); - QGLShader* fragShader = new QGLShader(QGLShader::FragmentShader, ctxGuard.context(), this); - fragShader->compile(source); + 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::VertexShader, ctxGuard.context(), this); - vertexShader->compile(source); + QGLShader* vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this); + vertexShader->compileSourceCode(source); #if defined(QT_DEBUG) // Name the shaders for easier debugging @@ -673,7 +673,7 @@ bool QGLEngineShaderManager::useCorrectShaderProg() currentShaderProg = sharedShaders->findProgramInCache(requiredProgram); if (currentShaderProg) { - currentShaderProg->program->enable(); + currentShaderProg->program->bind(); if (useCustomSrc) customSrcStage->setUniforms(currentShaderProg->program); } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index a9744b3..8228c7e 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -246,7 +246,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height) 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()->enable(); + pex->shaderManager->blitProgram()->bind(); pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); pex->shaderManager->setDirty(); @@ -395,7 +395,7 @@ void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush) void QGL2PaintEngineExPrivate::useSimpleShader() { - shaderManager->simpleProgram()->enable(); + shaderManager->simpleProgram()->bind(); shaderManager->setDirty(); if (matrixDirty) @@ -1203,7 +1203,9 @@ void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush) ensureActive(); QOpenGL2PaintEngineState *s = state(); - bool doOffset = !(s->renderHints & QPainter::Antialiasing) && style == Qt::SolidPattern; + bool doOffset = !(s->renderHints & QPainter::Antialiasing) && + (style == Qt::SolidPattern) && + !d->multisamplingAlwaysEnabled; if (doOffset) { d->temporaryTransform = s->matrix; @@ -1221,6 +1223,9 @@ void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush) } } +extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp + + void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) { Q_D(QGL2PaintEngineEx); @@ -1231,10 +1236,15 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) return; QOpenGL2PaintEngineState *s = state(); + if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) { + // QTriangulatingStroker class is not meant to support cosmetically sheared strokes. + QPaintEngineEx::stroke(path, pen); + return; + } ensureActive(); - bool doOffset = !(s->renderHints & QPainter::Antialiasing); + bool doOffset = !(s->renderHints & QPainter::Antialiasing) && !d->multisamplingAlwaysEnabled; if (doOffset) { d->temporaryTransform = s->matrix; QTransform tx = QTransform::fromTranslate(0.49, .49); @@ -1772,6 +1782,14 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) } #endif +#if defined(QT_OPENGL_ES_2) + // OpenGL ES can't switch MSAA off, so if the gl paint device is + // multisampled, it's always multisampled. + d->multisamplingAlwaysEnabled = d->device->format().sampleBuffers(); +#else + d->multisamplingAlwaysEnabled = false; +#endif + return true; } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 4cf2a83..9720723 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -277,6 +277,7 @@ public: bool needsSync; bool inRenderText; + bool multisamplingAlwaysEnabled; GLfloat depthRange[2]; diff --git a/src/opengl/gl2paintengineex/qtriangulatingstroker_p.h b/src/opengl/gl2paintengineex/qtriangulatingstroker_p.h index 97eabef..defa3f1 100644 --- a/src/opengl/gl2paintengineex/qtriangulatingstroker_p.h +++ b/src/opengl/gl2paintengineex/qtriangulatingstroker_p.h @@ -129,9 +129,9 @@ inline void QTriangulatingStroker::normalVector(float x1, float y1, float x2, fl float pw; if (dx == 0) - pw = m_width / dy; + pw = m_width / qAbs(dy); else if (dy == 0) - pw = m_width / dx; + pw = m_width / qAbs(dx); else pw = m_width / sqrt(dx*dx + dy*dy); @@ -259,8 +259,6 @@ void QTriangulatingStroker::lineTo(const qreal *pts) - - void QTriangulatingStroker::join(const qreal *pts) { // Creates a join to the next segment (m_cx, m_cy) -> (pts[0], pts[1]) diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index 7374594..d79283e 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -342,39 +342,6 @@ QGLContext *QGLFBOGLPaintDevice::context() const return fboContext; } -void QGLFBOGLPaintDevice::ensureActiveTarget() -{ - if (QGLContext::currentContext() != context()) - context()->makeCurrent(); - - QGLContext* ctx = const_cast<QGLContext*>(QGLContext::currentContext()); - Q_ASSERT(ctx); - const GLuint fboId = fbo->d_func()->fbo(); - if (ctx->d_func()->current_fbo != fboId) { - ctx->d_func()->current_fbo = fboId; - glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId); - } -} - -void QGLFBOGLPaintDevice::beginPaint() -{ - if (QGLContext::currentContext() != context()) - context()->makeCurrent(); - - // We let QFBO track the previously bound FBO rather than doing it - // ourselves here. This has the advantage that begin/release & bind/end - // work as expected. - wasBound = fbo->isBound(); - if (!wasBound) - fbo->bind(); -} - -void QGLFBOGLPaintDevice::endPaint() -{ - if (!wasBound) - fbo->release(); -} - bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const { QGL_FUNCP_CONTEXT; @@ -879,13 +846,6 @@ bool QGLFramebufferObject::isValid() const framebuffer to this framebuffer object. Returns true upon success, false otherwise. - Since 4.6: if another QGLFramebufferObject instance was already bound - to the current context, then its handle() will be remembered and - automatically restored when release() is called. This allows multiple - framebuffer rendering targets to be stacked up. It is important that - release() is called on the stacked framebuffer objects in the reverse - order of the calls to bind(). - \sa release() */ bool QGLFramebufferObject::bind() @@ -896,17 +856,18 @@ bool QGLFramebufferObject::bind() QGL_FUNC_CONTEXT; if (!ctx) return false; // Context no longer exists. + const QGLContext *current = QGLContext::currentContext(); +#ifdef QT_DEBUG + if (!current || + QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx)) + { + qWarning("QGLFramebufferObject::bind() called from incompatible context"); + } +#endif glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo()); d->valid = d->checkFramebufferStatus(); - const QGLContext *context = QGLContext::currentContext(); - if (d->valid && context) { - Q_ASSERT(QGLContextPrivate::contextGroup(context) == QGLContextPrivate::contextGroup(ctx)); - // Save the previous setting to automatically restore in release(). - if (context->d_ptr->current_fbo != d->fbo()) { - d->previous_fbo = context->d_ptr->current_fbo; - context->d_ptr->current_fbo = d->fbo(); - } - } + if (d->valid && current) + current->d_ptr->current_fbo = d->fbo(); return d->valid; } @@ -917,30 +878,29 @@ bool QGLFramebufferObject::bind() framebuffer. Returns true upon success, false otherwise. - Since 4.6: if another QGLFramebufferObject instance was already bound - to the current context when bind() was called, then this function will - automatically re-bind it to the current context. - \sa bind() */ bool QGLFramebufferObject::release() { if (!isValid()) return false; - Q_D(QGLFramebufferObject); QGL_FUNC_CONTEXT; if (!ctx) return false; // Context no longer exists. - const QGLContext *context = QGLContext::currentContext(); - if (context) { - Q_ASSERT(QGLContextPrivate::contextGroup(context) == QGLContextPrivate::contextGroup(ctx)); - // Restore the previous setting for stacked framebuffer objects. - if (d->previous_fbo != context->d_ptr->current_fbo) { - context->d_ptr->current_fbo = d->previous_fbo; - glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->previous_fbo); - } - d->previous_fbo = 0; + const QGLContext *current = QGLContext::currentContext(); + +#ifdef QT_DEBUG + if (!current || + QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx)) + { + qWarning("QGLFramebufferObject::release() called from incompatible context"); + } +#endif + + if (current) { + current->d_ptr->current_fbo = 0; + glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); } return true; diff --git a/src/opengl/qglframebufferobject_p.h b/src/opengl/qglframebufferobject_p.h index 122c42e..800cb68 100644 --- a/src/opengl/qglframebufferobject_p.h +++ b/src/opengl/qglframebufferobject_p.h @@ -111,9 +111,6 @@ public: virtual QSize size() const {return fbo->size();} virtual QGLContext* context() const; virtual QGLFormat format() const {return fboFormat;} - virtual void ensureActiveTarget(); - virtual void beginPaint(); - virtual void endPaint(); void setFBO(QGLFramebufferObject* f, QGLFramebufferObject::Attachment attachment); @@ -127,7 +124,8 @@ private: class QGLFramebufferObjectPrivate { public: - QGLFramebufferObjectPrivate() : fbo_guard(0), texture(0), depth_stencil_buffer(0), color_buffer(0), valid(false), previous_fbo(0), engine(0) {} + QGLFramebufferObjectPrivate() : fbo_guard(0), texture(0), depth_stencil_buffer(0) + , color_buffer(0), valid(false), engine(0) {} ~QGLFramebufferObjectPrivate() {} void init(QGLFramebufferObject *q, const QSize& sz, @@ -143,7 +141,6 @@ public: QGLFramebufferObjectFormat format; uint valid : 1; QGLFramebufferObject::Attachment fbo_attachment; - GLuint previous_fbo; mutable QPaintEngine *engine; QGLFBOGLPaintDevice glDevice; diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index e28c382..b4191dc 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -69,7 +69,7 @@ QT_BEGIN_NAMESPACE The following example creates a vertex shader program using the supplied source \c{code}. Once compiled and linked, the shader program is activated in the current QGLContext by calling - QGLShaderProgram::enable(): + QGLShaderProgram::bind(): \snippet doc/src/snippets/code/src_opengl_qglshaderprogram.cpp 0 @@ -125,11 +125,11 @@ QT_BEGIN_NAMESPACE */ /*! - \enum QGLShader::ShaderTypeBits + \enum QGLShader::ShaderTypeBit This enum specifies the type of QGLShader that is being created. - \value VertexShader Vertex shader written in the OpenGL Shading Language (GLSL). - \value FragmentShader Fragment shader written in the OpenGL Shading Language (GLSL). + \value Vertex Vertex shader written in the OpenGL Shading Language (GLSL). + \value Fragment Fragment shader written in the OpenGL Shading Language (GLSL). */ #ifndef GL_FRAGMENT_SHADER @@ -211,7 +211,7 @@ bool QGLShaderPrivate::create() return false; if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) { GLuint shader; - if (shaderType == QGLShader::VertexShader) + if (shaderType == QGLShader::Vertex) shader = glCreateShader(GL_VERTEX_SHADER); else shader = glCreateShader(GL_FRAGMENT_SHADER); @@ -266,14 +266,14 @@ void QGLShaderPrivate::deleteShader() /*! Constructs a new QGLShader object of the specified \a type and attaches it to \a parent. If shader programs are not supported, - QGLShaderProgram::hasShaderPrograms() will return false. + QGLShaderProgram::hasOpenGLShaderPrograms() will return false. - This constructor is normally followed by a call to compile() - or compileFile(). + This constructor is normally followed by a call to compileSourceCode() + or compileSourceFile(). The shader will be associated with the current QGLContext. - \sa compile(), compileFile() + \sa compileSourceCode(), compileSourceFile() */ QGLShader::QGLShader(QGLShader::ShaderType type, QObject *parent) : QObject(*new QGLShaderPrivate(QGLContext::currentContext(), type), parent) @@ -283,45 +283,19 @@ QGLShader::QGLShader(QGLShader::ShaderType type, QObject *parent) } /*! - Constructs a new QGLShader object of the specified \a type from the - source code in \a fileName and attaches it to \a parent. - If the shader could not be loaded, then isCompiled() will return false. - - The shader will be associated with the current QGLContext. - - \sa isCompiled() -*/ -QGLShader::QGLShader - (const QString& fileName, QGLShader::ShaderType type, QObject *parent) - : QObject(*new QGLShaderPrivate(QGLContext::currentContext(), type), parent) -{ - Q_D(QGLShader); - if (d->create() && !compileFile(fileName)) - d->deleteShader(); -} - -static inline const QGLContext *contextOrCurrent(const QGLContext *context) -{ - if (context) - return context; - else - return QGLContext::currentContext(); -} - -/*! Constructs a new QGLShader object of the specified \a type and attaches it to \a parent. If shader programs are not supported, - then QGLShaderProgram::hasShaderPrograms() will return false. + then QGLShaderProgram::hasOpenGLShaderPrograms() will return false. - This constructor is normally followed by a call to compile() - or compileFile(). + This constructor is normally followed by a call to compileSourceCode() + or compileSourceFile(). The shader will be associated with \a context. - \sa compile(), compileFile() + \sa compileSourceCode(), compileSourceFile() */ QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent) - : QObject(*new QGLShaderPrivate(contextOrCurrent(context), type), parent) + : QObject(*new QGLShaderPrivate(context ? context : QGLContext::currentContext(), type), parent) { Q_D(QGLShader); #ifndef QT_NO_DEBUG @@ -334,30 +308,6 @@ QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObj } /*! - Constructs a new QGLShader object of the specified \a type from the - source code in \a fileName and attaches it to \a parent. - If the shader could not be loaded, then isCompiled() will return false. - - The shader will be associated with \a context. - - \sa isCompiled() -*/ -QGLShader::QGLShader - (const QString& fileName, QGLShader::ShaderType type, const QGLContext *context, QObject *parent) - : QObject(*new QGLShaderPrivate(contextOrCurrent(context), type), parent) -{ - Q_D(QGLShader); -#ifndef QT_NO_DEBUG - if (context && !QGLContext::areSharing(context, QGLContext::currentContext())) { - qWarning("QGLShader::QGLShader: \'context\' must be current context or sharing with it."); - return; - } -#endif - if (d->create() && !compileFile(fileName)) - d->deleteShader(); -} - -/*! Deletes this shader. If the shader has been attached to a QGLShaderProgram object, then the actual shader will stay around until the QGLShaderProgram is destroyed. @@ -400,9 +350,9 @@ static const char redefineHighp[] = Sets the \a source code for this shader and compiles it. Returns true if the source was successfully compiled, false otherwise. - \sa compileFile() + \sa compileSourceFile() */ -bool QGLShader::compile(const char *source) +bool QGLShader::compileSourceCode(const char *source) { Q_D(QGLShader); if (d->shaderGuard.id()) { @@ -431,7 +381,7 @@ bool QGLShader::compile(const char *source) srclen.append(GLint(sizeof(qualifierDefines) - 1)); #endif #ifdef QGL_REDEFINE_HIGHP - if (d->shaderType == FragmentShader) { + if (d->shaderType == Fragment) { src.append(redefineHighp); srclen.append(GLint(sizeof(redefineHighp) - 1)); } @@ -451,11 +401,11 @@ bool QGLShader::compile(const char *source) Sets the \a source code for this shader and compiles it. Returns true if the source was successfully compiled, false otherwise. - \sa compileFile() + \sa compileSourceFile() */ -bool QGLShader::compile(const QByteArray& source) +bool QGLShader::compileSourceCode(const QByteArray& source) { - return compile(source.constData()); + return compileSourceCode(source.constData()); } /*! @@ -464,11 +414,11 @@ bool QGLShader::compile(const QByteArray& source) Sets the \a source code for this shader and compiles it. Returns true if the source was successfully compiled, false otherwise. - \sa compileFile() + \sa compileSourceFile() */ -bool QGLShader::compile(const QString& source) +bool QGLShader::compileSourceCode(const QString& source) { - return compile(source.toLatin1().constData()); + return compileSourceCode(source.toLatin1().constData()); } /*! @@ -476,9 +426,9 @@ bool QGLShader::compile(const QString& source) and compiles it. Returns true if the file could be opened and the source compiled, false otherwise. - \sa compile() + \sa compileSourceCode() */ -bool QGLShader::compileFile(const QString& fileName) +bool QGLShader::compileSourceFile(const QString& fileName) { QFile file(fileName); if (!file.open(QFile::ReadOnly)) { @@ -487,13 +437,13 @@ bool QGLShader::compileFile(const QString& fileName) } QByteArray contents = file.readAll(); - return compile(contents.constData()); + return compileSourceCode(contents.constData()); } /*! Returns the source code for this shader. - \sa compile() + \sa compileSourceCode() */ QByteArray QGLShader::sourceCode() const { @@ -516,7 +466,7 @@ QByteArray QGLShader::sourceCode() const /*! Returns true if this shader has been compiled; false otherwise. - \sa compile() + \sa compileSourceCode(), compileSourceFile() */ bool QGLShader::isCompiled() const { @@ -527,7 +477,7 @@ bool QGLShader::isCompiled() const /*! Returns the errors and warnings that occurred during the last compile. - \sa compile() + \sa compileSourceCode(), compileSourceFile() */ QString QGLShader::log() const { @@ -666,6 +616,7 @@ bool QGLShaderProgram::init() is deleted. This allows the caller to add the same shader to multiple shader programs. + \sa addShaderFromSourceCode(), addShaderFromSourceFile() \sa removeShader(), link(), removeAllShaders() */ bool QGLShaderProgram::addShader(QGLShader *shader) @@ -705,15 +656,16 @@ bool QGLShaderProgram::addShader(QGLShader *shader) adding vertex and fragment shaders to a shader program without creating an instance of QGLShader first. + \sa addShader(), addShaderFromSourceFile() \sa removeShader(), link(), log(), removeAllShaders() */ -bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const char *source) +bool QGLShaderProgram::addShaderFromSourceCode(QGLShader::ShaderType type, const char *source) { Q_D(QGLShaderProgram); if (!init()) return false; QGLShader *shader = new QGLShader(type, this); - if (!shader->compile(source)) { + if (!shader->compileSourceCode(source)) { d->log = shader->log(); delete shader; return false; @@ -734,11 +686,12 @@ bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const char *source) adding vertex and fragment shaders to a shader program without creating an instance of QGLShader first. + \sa addShader(), addShaderFromSourceFile() \sa removeShader(), link(), log(), removeAllShaders() */ -bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QByteArray& source) +bool QGLShaderProgram::addShaderFromSourceCode(QGLShader::ShaderType type, const QByteArray& source) { - return addShader(type, source.constData()); + return addShaderFromSourceCode(type, source.constData()); } /*! @@ -753,11 +706,12 @@ bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QByteArray& s adding vertex and fragment shaders to a shader program without creating an instance of QGLShader first. + \sa addShader(), addShaderFromSourceFile() \sa removeShader(), link(), log(), removeAllShaders() */ -bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QString& source) +bool QGLShaderProgram::addShaderFromSourceCode(QGLShader::ShaderType type, const QString& source) { - return addShader(type, source.toLatin1().constData()); + return addShaderFromSourceCode(type, source.toLatin1().constData()); } /*! @@ -770,16 +724,16 @@ bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QString& sour adding vertex and fragment shaders to a shader program without creating an instance of QGLShader first. - \sa addShader() + \sa addShader(), addShaderFromSourceCode() */ -bool QGLShaderProgram::addShaderFromFile +bool QGLShaderProgram::addShaderFromSourceFile (QGLShader::ShaderType type, const QString& fileName) { Q_D(QGLShaderProgram); if (!init()) return false; QGLShader *shader = new QGLShader(type, this); - if (!shader->compileFile(fileName)) { + if (!shader->compileSourceFile(fileName)) { d->log = shader->log(); delete shader; return false; @@ -912,14 +866,16 @@ QString QGLShaderProgram::log() const } /*! - Enable use of this shader program in the currently active QGLContext. - Returns true if the program was successfully enabled; false - otherwise. If the shader program has not yet been linked, + Binds this shader program to the active QGLContext and makes + it the current shader program. Any previously bound shader program + is released. This is equivalent to calling \c{glUseProgram()} on + programId(). Returns true if the program was successfully bound; + false otherwise. If the shader program has not yet been linked, or it needs to be re-linked, this function will call link(). - \sa link(), disable() + \sa link(), release() */ -bool QGLShaderProgram::enable() +bool QGLShaderProgram::bind() { Q_D(QGLShaderProgram); GLuint program = d->programGuard.id(); @@ -927,6 +883,12 @@ bool QGLShaderProgram::enable() return false; if (!d->linked && !link()) return false; +#ifndef QT_NO_DEBUG + if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext())) { + qWarning("QGLShaderProgram::bind: program is not valid in the current context."); + return false; + } +#endif glUseProgram(program); return true; } @@ -935,13 +897,18 @@ bool QGLShaderProgram::enable() #define ctx QGLContext::currentContext() /*! - Disables the active shader program in the current QGLContext. + Releases the active shader program from the current QGLContext. This is equivalent to calling \c{glUseProgram(0)}. - \sa enable() + \sa bind() */ -void QGLShaderProgram::disable() +void QGLShaderProgram::release() { +#ifndef QT_NO_DEBUG + Q_D(QGLShaderProgram); + if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext())) + qWarning("QGLShaderProgram::release: program is not valid in the current context."); +#endif #if defined(QT_OPENGL_ES_2) glUseProgram(0); #else @@ -1331,22 +1298,26 @@ void QGLShaderProgram::setAttributeValue /*! Sets an array of vertex \a values on the attribute at \a location - in this shader program. The \a size indicates the number of + in this shader program. The \a tupleSize indicates the number of components per vertex (1, 2, 3, or 4), and the \a stride indicates the number of bytes between vertices. A default \a stride value of zero indicates that the vertices are densely packed in \a values. - \sa setAttributeValue(), setUniformValue(), disableAttributeArray() + The array will become active when enableAttributeArray() is called + on the \a location. Otherwise the value specified with + setAttributeValue() for \a location will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() */ void QGLShaderProgram::setAttributeArray - (int location, const GLfloat *values, int size, int stride) + (int location, const GLfloat *values, int tupleSize, int stride) { Q_D(QGLShaderProgram); Q_UNUSED(d); if (location != -1) { - glVertexAttribPointer(location, size, GL_FLOAT, GL_FALSE, + glVertexAttribPointer(location, tupleSize, GL_FLOAT, GL_FALSE, stride, values); - glEnableVertexAttribArray(location); } } @@ -1356,7 +1327,12 @@ void QGLShaderProgram::setAttributeArray between vertices. A default \a stride value of zero indicates that the vertices are densely packed in \a values. - \sa setAttributeValue(), setUniformValue(), disableAttributeArray() + The array will become active when enableAttributeArray() is called + on the \a location. Otherwise the value specified with + setAttributeValue() for \a location will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() */ void QGLShaderProgram::setAttributeArray (int location, const QVector2D *values, int stride) @@ -1366,7 +1342,6 @@ void QGLShaderProgram::setAttributeArray if (location != -1) { glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, stride, values); - glEnableVertexAttribArray(location); } } @@ -1376,7 +1351,12 @@ void QGLShaderProgram::setAttributeArray between vertices. A default \a stride value of zero indicates that the vertices are densely packed in \a values. - \sa setAttributeValue(), setUniformValue(), disableAttributeArray() + The array will become active when enableAttributeArray() is called + on the \a location. Otherwise the value specified with + setAttributeValue() for \a location will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() */ void QGLShaderProgram::setAttributeArray (int location, const QVector3D *values, int stride) @@ -1386,7 +1366,6 @@ void QGLShaderProgram::setAttributeArray if (location != -1) { glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, stride, values); - glEnableVertexAttribArray(location); } } @@ -1396,7 +1375,12 @@ void QGLShaderProgram::setAttributeArray between vertices. A default \a stride value of zero indicates that the vertices are densely packed in \a values. - \sa setAttributeValue(), setUniformValue(), disableAttributeArray() + The array will become active when enableAttributeArray() is called + on the \a location. Otherwise the value specified with + setAttributeValue() for \a location will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() */ void QGLShaderProgram::setAttributeArray (int location, const QVector4D *values, int stride) @@ -1406,7 +1390,6 @@ void QGLShaderProgram::setAttributeArray if (location != -1) { glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, stride, values); - glEnableVertexAttribArray(location); } } @@ -1414,17 +1397,22 @@ void QGLShaderProgram::setAttributeArray \overload Sets an array of vertex \a values on the attribute called \a name - in this shader program. The \a size indicates the number of + in this shader program. The \a tupleSize indicates the number of components per vertex (1, 2, 3, or 4), and the \a stride indicates the number of bytes between vertices. A default \a stride value of zero indicates that the vertices are densely packed in \a values. - \sa setAttributeValue(), setUniformValue(), disableAttributeArray() + The array will become active when enableAttributeArray() is called + on \a name. Otherwise the value specified with setAttributeValue() + for \a name will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() */ void QGLShaderProgram::setAttributeArray - (const char *name, const GLfloat *values, int size, int stride) + (const char *name, const GLfloat *values, int tupleSize, int stride) { - setAttributeArray(attributeLocation(name), values, size, stride); + setAttributeArray(attributeLocation(name), values, tupleSize, stride); } /*! @@ -1435,7 +1423,12 @@ void QGLShaderProgram::setAttributeArray between vertices. A default \a stride value of zero indicates that the vertices are densely packed in \a values. - \sa setAttributeValue(), setUniformValue(), disableAttributeArray() + The array will become active when enableAttributeArray() is called + on \a name. Otherwise the value specified with setAttributeValue() + for \a name will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() */ void QGLShaderProgram::setAttributeArray (const char *name, const QVector2D *values, int stride) @@ -1451,7 +1444,12 @@ void QGLShaderProgram::setAttributeArray between vertices. A default \a stride value of zero indicates that the vertices are densely packed in \a values. - \sa setAttributeValue(), setUniformValue(), disableAttributeArray() + The array will become active when enableAttributeArray() is called + on \a name. Otherwise the value specified with setAttributeValue() + for \a name will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() */ void QGLShaderProgram::setAttributeArray (const char *name, const QVector3D *values, int stride) @@ -1467,7 +1465,12 @@ void QGLShaderProgram::setAttributeArray between vertices. A default \a stride value of zero indicates that the vertices are densely packed in \a values. - \sa setAttributeValue(), setUniformValue(), disableAttributeArray() + The array will become active when enableAttributeArray() is called + on \a name. Otherwise the value specified with setAttributeValue() + for \a name will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() */ void QGLShaderProgram::setAttributeArray (const char *name, const QVector4D *values, int stride) @@ -1476,10 +1479,42 @@ void QGLShaderProgram::setAttributeArray } /*! + Enables the vertex array at \a location in this shader program + so that the value set by setAttributeArray() on \a location + will be used by the shader program. + + \sa disableAttributeArray(), setAttributeArray(), setAttributeValue() + \sa setUniformValue() +*/ +void QGLShaderProgram::enableAttributeArray(int location) +{ + Q_D(QGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + glEnableVertexAttribArray(location); +} + +/*! + \overload + + Enables the vertex array called \a name in this shader program + so that the value set by setAttributeArray() on \a name + will be used by the shader program. + + \sa disableAttributeArray(), setAttributeArray(), setAttributeValue() + \sa setUniformValue() +*/ +void QGLShaderProgram::enableAttributeArray(const char *name) +{ + enableAttributeArray(attributeLocation(name)); +} + +/*! Disables the vertex array at \a location in this shader program - that was enabled by a previous call to setAttributeArray(). + that was enabled by a previous call to enableAttributeArray(). - \sa setAttributeArray(), setAttributeValue(), setUniformValue() + \sa enableAttributeArray(), setAttributeArray(), setAttributeValue() + \sa setUniformValue() */ void QGLShaderProgram::disableAttributeArray(int location) { @@ -1493,9 +1528,10 @@ void QGLShaderProgram::disableAttributeArray(int location) \overload Disables the vertex array called \a name in this shader program - that was enabled by a previous call to setAttributeArray(). + that was enabled by a previous call to enableAttributeArray(). - \sa setAttributeArray(), setAttributeValue(), setUniformValue() + \sa enableAttributeArray(), setAttributeArray(), setAttributeValue() + \sa setUniformValue() */ void QGLShaderProgram::disableAttributeArray(const char *name) { @@ -2363,25 +2399,25 @@ void QGLShaderProgram::setUniformValueArray /*! Sets the uniform variable array at \a location in the current context to the \a count elements of \a values. Each element - has \a size components. The \a size must be 1, 2, 3, or 4. + has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4. \sa setAttributeValue() */ -void QGLShaderProgram::setUniformValueArray(int location, const GLfloat *values, int count, int size) +void QGLShaderProgram::setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize) { Q_D(QGLShaderProgram); Q_UNUSED(d); if (location != -1) { - if (size == 1) + if (tupleSize == 1) glUniform1fv(location, count, values); - else if (size == 2) + else if (tupleSize == 2) glUniform2fv(location, count, values); - else if (size == 3) + else if (tupleSize == 3) glUniform3fv(location, count, values); - else if (size == 4) + else if (tupleSize == 4) glUniform4fv(location, count, values); else - qWarning() << "QGLShaderProgram::setUniformValue: size" << size << "not supported"; + qWarning() << "QGLShaderProgram::setUniformValue: size" << tupleSize << "not supported"; } } @@ -2390,14 +2426,14 @@ void QGLShaderProgram::setUniformValueArray(int location, const GLfloat *values, Sets the uniform variable array called \a name in the current context to the \a count elements of \a values. Each element - has \a size components. The \a size must be 1, 2, 3, or 4. + has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4. \sa setAttributeValue() */ void QGLShaderProgram::setUniformValueArray - (const char *name, const GLfloat *values, int count, int size) + (const char *name, const GLfloat *values, int count, int tupleSize) { - setUniformValueArray(uniformLocation(name), values, count, size); + setUniformValueArray(uniformLocation(name), values, count, tupleSize); } /*! @@ -2800,7 +2836,7 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 * The \a context is used to resolve the GLSL extensions. If \a context is null, then QGLContext::currentContext() is used. */ -bool QGLShaderProgram::hasShaderPrograms(const QGLContext *context) +bool QGLShaderProgram::hasOpenGLShaderPrograms(const QGLContext *context) { #if !defined(QT_OPENGL_ES_2) if (!context) @@ -2825,8 +2861,6 @@ void QGLShaderProgram::shaderDestroyed() removeShader(shader); } -#endif - #ifdef Q_MAC_COMPAT_GL_FUNCTIONS /*! \internal */ void QGLShaderProgram::setUniformValue(int location, QMacCompatGLint value) @@ -2877,4 +2911,6 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMacCompatGL } #endif +#endif // !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1) + QT_END_NAMESPACE diff --git a/src/opengl/qglshaderprogram.h b/src/opengl/qglshaderprogram.h index 49c3364..deeaee2 100644 --- a/src/opengl/qglshaderprogram.h +++ b/src/opengl/qglshaderprogram.h @@ -63,25 +63,23 @@ class Q_OPENGL_EXPORT QGLShader : public QObject { Q_OBJECT public: - enum ShaderTypeBits + enum ShaderTypeBit { - VertexShader = 0x0001, - FragmentShader = 0x0002 + Vertex = 0x0001, + Fragment = 0x0002 }; - Q_DECLARE_FLAGS(ShaderType, ShaderTypeBits) + Q_DECLARE_FLAGS(ShaderType, ShaderTypeBit) explicit QGLShader(QGLShader::ShaderType type, QObject *parent = 0); - QGLShader(const QString& fileName, QGLShader::ShaderType type, QObject *parent = 0); QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent = 0); - QGLShader(const QString& fileName, QGLShader::ShaderType type, const QGLContext *context, QObject *parent = 0); virtual ~QGLShader(); QGLShader::ShaderType shaderType() const; - bool compile(const char *source); - bool compile(const QByteArray& source); - bool compile(const QString& source); - bool compileFile(const QString& fileName); + bool compileSourceCode(const char *source); + bool compileSourceCode(const QByteArray& source); + bool compileSourceCode(const QString& source); + bool compileSourceFile(const QString& fileName); QByteArray sourceCode() const; @@ -114,10 +112,10 @@ public: void removeShader(QGLShader *shader); QList<QGLShader *> shaders() const; - bool addShader(QGLShader::ShaderType type, const char *source); - bool addShader(QGLShader::ShaderType type, const QByteArray& source); - bool addShader(QGLShader::ShaderType type, const QString& source); - bool addShaderFromFile(QGLShader::ShaderType type, const QString& fileName); + bool addShaderFromSourceCode(QGLShader::ShaderType type, const char *source); + bool addShaderFromSourceCode(QGLShader::ShaderType type, const QByteArray& source); + bool addShaderFromSourceCode(QGLShader::ShaderType type, const QString& source); + bool addShaderFromSourceFile(QGLShader::ShaderType type, const QString& fileName); void removeAllShaders(); @@ -125,8 +123,8 @@ public: bool isLinked() const; QString log() const; - bool enable(); - static void disable(); + bool bind(); + void release(); GLuint programId() const; @@ -159,7 +157,7 @@ public: void setAttributeValue(const char *name, const GLfloat *values, int columns, int rows); void setAttributeArray - (int location, const GLfloat *values, int size, int stride = 0); + (int location, const GLfloat *values, int tupleSize, int stride = 0); void setAttributeArray (int location, const QVector2D *values, int stride = 0); void setAttributeArray @@ -167,13 +165,16 @@ public: void setAttributeArray (int location, const QVector4D *values, int stride = 0); void setAttributeArray - (const char *name, const GLfloat *values, int size, int stride = 0); + (const char *name, const GLfloat *values, int tupleSize, int stride = 0); void setAttributeArray (const char *name, const QVector2D *values, int stride = 0); void setAttributeArray (const char *name, const QVector3D *values, int stride = 0); void setAttributeArray (const char *name, const QVector4D *values, int stride = 0); + + void enableAttributeArray(int location); + void enableAttributeArray(const char *name); void disableAttributeArray(int location); void disableAttributeArray(const char *name); @@ -244,7 +245,7 @@ public: void setUniformValue(const char *name, const GLfloat value[4][4]); void setUniformValue(const char *name, const QTransform& value); - void setUniformValueArray(int location, const GLfloat *values, int count, int size); + void setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize); void setUniformValueArray(int location, const GLint *values, int count); void setUniformValueArray(int location, const GLuint *values, int count); void setUniformValueArray(int location, const QVector2D *values, int count); @@ -260,7 +261,7 @@ public: void setUniformValueArray(int location, const QMatrix4x3 *values, int count); void setUniformValueArray(int location, const QMatrix4x4 *values, int count); - void setUniformValueArray(const char *name, const GLfloat *values, int count, int size); + void setUniformValueArray(const char *name, const GLfloat *values, int count, int tupleSize); void setUniformValueArray(const char *name, const GLint *values, int count); void setUniformValueArray(const char *name, const GLuint *values, int count); void setUniformValueArray(const char *name, const QVector2D *values, int count); @@ -276,7 +277,7 @@ public: void setUniformValueArray(const char *name, const QMatrix4x3 *values, int count); void setUniformValueArray(const char *name, const QMatrix4x4 *values, int count); - static bool hasShaderPrograms(const QGLContext *context = 0); + static bool hasOpenGLShaderPrograms(const QGLContext *context = 0); private Q_SLOTS: void shaderDestroyed(); diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp index ebe101d..f1f5976 100644 --- a/src/opengl/qwindowsurface_gl.cpp +++ b/src/opengl/qwindowsurface_gl.cpp @@ -625,7 +625,7 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint & QGLShaderProgram *blitProgram = QGLEngineSharedShaders::shadersForContext(ctx)->blitProgram(); - blitProgram->enable(); + blitProgram->bind(); blitProgram->setUniformValue("imageTexture", 0 /*QT_IMAGE_TEXTURE_UNIT*/); // The shader manager's blit program does not multiply the diff --git a/src/opengl/util/composition_mode_softlight.glsl b/src/opengl/util/composition_mode_softlight.glsl index 4777b74..e4c1f89 100644 --- a/src/opengl/util/composition_mode_softlight.glsl +++ b/src/opengl/util/composition_mode_softlight.glsl @@ -1,18 +1,22 @@ -// Dca' = 2.Sca < Sa ? -// Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa) : -// (8.Dca <= Da ? -// Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa).(3 - 8.Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) : -// (Dca.Sa + ((Dca/Da)^(0.5).Da - Dca).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa)) +// if 2.Sca <= Sa +// Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) +// otherwise if 2.Sca > Sa and 4.Dca <= Da +// Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) +// otherwise if 2.Sca > Sa and 4.Dca > Da +// Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) // Da' = Sa + Da - Sa.Da + vec4 composite(vec4 src, vec4 dst) { vec4 result; float da = max(dst.a, 0.00001); - result.rgb = mix(dst.rgb * (src.a - (1.0 - dst.rgb / da) * (2.0 * src.rgb - src.a)), - mix(dst.rgb * (src.a - (1.0 - dst.rgb / da) * (2.0 * src.rgb - src.a) * (3.0 - 8.0 * dst.rgb / da)), - (dst.rgb * src.a + (sqrt(dst.rgb / da) * dst.a - dst.rgb) * (2.0 * src.rgb - src.a)), - step(dst.a, 8.0 * dst.rgb)), - step(src.a, 2.0 * src.rgb)) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a); + vec3 dst_np = dst.rgb / da; + result.rgb = mix(dst.rgb * (src.a + (2.0 * src.rgb - src.a) * (1.0 - dst_np)), + mix(dst.rgb * src.a + dst.a * (2.0 * src.rgb - src.a) * ((16.0 * dst_np - 12.0) * dst_np + 3.0) * dst_np, + dst.rgb * src.a + dst.a * (2.0 * src.rgb - src.a) * (sqrt(dst_np) - dst_np), + step(dst.a, 4.0 * dst.rgb)), + step(src.a, 2.0 * src.rgb)) + + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a); result.a = src.a + dst.a - src.a * dst.a; return result; } diff --git a/src/opengl/util/fragmentprograms_p.h b/src/opengl/util/fragmentprograms_p.h index 9154c6e..2241057 100644 --- a/src/opengl/util/fragmentprograms_p.h +++ b/src/opengl/util/fragmentprograms_p.h @@ -519,8 +519,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SOFTLIGHT = "!!ARBfp1.0\n" "PARAM c[6] = { program.local[0..3],\n" - " { 1, 2, 9.9999997e-006, 8 },\n" - " { 3 } };\n" + " { 1, 2, 9.9999997e-006, 4 },\n" + " { 16, 12, 3 } };\n" "TEMP R0;\n" "TEMP R1;\n" "TEMP R2;\n" @@ -530,30 +530,31 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE "MUL R0.xy, fragment.position, c[1];\n" "TEX R0, R0, texture[0], 2D;\n" "MAX R1.x, R0.w, c[4].z;\n" - "RCP R1.w, R1.x;\n" - "MUL R1.xyz, R0, R1.w;\n" - "MUL R4.xyz, -R1, c[4].w;\n" - "RSQ R2.x, R1.x;\n" - "RSQ R2.z, R1.z;\n" - "RSQ R2.y, R1.y;\n" - "MAD R1.xyz, -R0, R1.w, c[4].x;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.z, R2.z;\n" - "RCP R2.y, R2.y;\n" - "MAD R3.xyz, R0.w, R2, -R0;\n" - "MAD R2.xyz, fragment.color.primary, c[4].y, -fragment.color.primary.w;\n" - "MUL R3.xyz, R2, R3;\n" - "ADD R5.xyz, R4, c[5].x;\n" - "MUL R4.xyz, R1, R2;\n" - "MAD R1.xyz, -R1, R2, fragment.color.primary.w;\n" + "RCP R1.x, R1.x;\n" + "MUL R2.xyz, R0, R1.x;\n" + "MAD R1.xyz, R2, c[5].x, -c[5].y;\n" + "MAD R3.xyz, R2, R1, c[5].z;\n" + "MAD R1.xyz, fragment.color.primary, c[4].y, -fragment.color.primary.w;\n" + "MUL R4.xyz, R0.w, R1;\n" + "MUL R5.xyz, R4, R3;\n" + "RSQ R1.w, R2.x;\n" + "RSQ R2.w, R2.z;\n" + "RCP R3.x, R1.w;\n" + "RSQ R1.w, R2.y;\n" + "MUL R5.xyz, R2, R5;\n" + "RCP R3.z, R2.w;\n" + "RCP R3.y, R1.w;\n" + "ADD R3.xyz, -R2, R3;\n" + "MUL R3.xyz, R4, R3;\n" + "ADD R2.xyz, -R2, c[4].x;\n" + "MAD R1.xyz, R1, R2, fragment.color.primary.w;\n" "MUL R2.xyz, fragment.color.primary, c[4].y;\n" - "MAD R5.xyz, -R4, R5, fragment.color.primary.w;\n" + "MAD R4.xyz, fragment.color.primary.w, R0, R5;\n" "MAD R3.xyz, fragment.color.primary.w, R0, R3;\n" - "MAD R4.xyz, -R0, R5, R3;\n" + "ADD R5.xyz, R3, -R4;\n" "MUL R3.xyz, R0, c[4].w;\n" - "MUL R5.xyz, R0, R5;\n" "SGE R3.xyz, R3, R0.w;\n" - "MAD R3.xyz, R3, R4, R5;\n" + "MAD R3.xyz, R3, R5, R4;\n" "MAD R3.xyz, -R0, R1, R3;\n" "MUL R1.xyz, R0, R1;\n" "SGE R2.xyz, R2, fragment.color.primary.w;\n" @@ -861,8 +862,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SOFTLIGHT_NOMASK = "!!ARBfp1.0\n" "PARAM c[3] = { program.local[0],\n" - " { 1, 2, 9.9999997e-006, 8 },\n" - " { 3 } };\n" + " { 1, 2, 9.9999997e-006, 4 },\n" + " { 16, 12, 3 } };\n" "TEMP R0;\n" "TEMP R1;\n" "TEMP R2;\n" @@ -872,30 +873,31 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE "MUL R0.xy, fragment.position, c[0];\n" "TEX R0, R0, texture[0], 2D;\n" "MAX R1.x, R0.w, c[1].z;\n" - "RCP R1.w, R1.x;\n" - "MUL R1.xyz, R0, R1.w;\n" - "MUL R4.xyz, -R1, c[1].w;\n" - "RSQ R2.x, R1.x;\n" - "RSQ R2.z, R1.z;\n" - "RSQ R2.y, R1.y;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.z, R2.z;\n" - "RCP R2.y, R2.y;\n" - "MAD R3.xyz, R0.w, R2, -R0;\n" - "MAD R2.xyz, fragment.color.primary, c[1].y, -fragment.color.primary.w;\n" - "MUL R3.xyz, R2, R3;\n" + "RCP R1.x, R1.x;\n" + "MUL R2.xyz, R0, R1.x;\n" + "MAD R1.xyz, R2, c[2].x, -c[2].y;\n" + "MAD R3.xyz, R2, R1, c[2].z;\n" + "MAD R1.xyz, fragment.color.primary, c[1].y, -fragment.color.primary.w;\n" + "MUL R4.xyz, R0.w, R1;\n" + "MUL R5.xyz, R4, R3;\n" + "RSQ R1.w, R2.x;\n" + "RCP R3.x, R1.w;\n" + "RSQ R2.w, R2.z;\n" + "RSQ R1.w, R2.y;\n" + "MUL R5.xyz, R2, R5;\n" + "RCP R3.z, R2.w;\n" + "RCP R3.y, R1.w;\n" + "ADD R3.xyz, -R2, R3;\n" + "MUL R3.xyz, R4, R3;\n" + "ADD R2.xyz, -R2, c[1].x;\n" + "MAD R1.xyz, R1, R2, fragment.color.primary.w;\n" + "MUL R2.xyz, fragment.color.primary, c[1].y;\n" + "MAD R4.xyz, fragment.color.primary.w, R0, R5;\n" "MAD R3.xyz, fragment.color.primary.w, R0, R3;\n" - "MAD R1.xyz, -R0, R1.w, c[1].x;\n" - "ADD R5.xyz, R4, c[2].x;\n" - "MUL R4.xyz, R1, R2;\n" - "MAD R1.xyz, -R1, R2, fragment.color.primary.w;\n" - "MAD R5.xyz, -R4, R5, fragment.color.primary.w;\n" - "MAD R4.xyz, -R0, R5, R3;\n" + "ADD R5.xyz, R3, -R4;\n" "MUL R3.xyz, R0, c[1].w;\n" - "MUL R2.xyz, fragment.color.primary, c[1].y;\n" - "MUL R5.xyz, R0, R5;\n" "SGE R3.xyz, R3, R0.w;\n" - "MAD R3.xyz, R3, R4, R5;\n" + "MAD R3.xyz, R3, R5, R4;\n" "MAD R3.xyz, -R0, R1, R3;\n" "MUL R1.xyz, R0, R1;\n" "SGE R2.xyz, R2, fragment.color.primary.w;\n" @@ -1457,7 +1459,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD "!!ARBfp1.0\n" "PARAM c[11] = { program.local[0..8],\n" " { 2, 4, 1, 9.9999997e-006 },\n" - " { 8, 3 } };\n" + " { 16, 12, 3 } };\n" "TEMP R0;\n" "TEMP R1;\n" "TEMP R2;\n" @@ -1469,53 +1471,55 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD "MAD R0.xyz, fragment.position.x, c[2], R0;\n" "ADD R0.xyz, R0, c[4];\n" "RCP R0.z, R0.z;\n" - "MUL R1.xy, fragment.position, c[6];\n" - "TEX R1, R1, texture[0], 2D;\n" - "MAX R0.w, R1, c[9];\n" - "RCP R2.w, R0.w;\n" - "MUL R5.xyz, R1, R2.w;\n" "MUL R0.xy, R0, R0.z;\n" "MUL R0.zw, R0.xyxy, R0.xyxy;\n" "ADD R0.z, R0, R0.w;\n" "MUL R0.xy, R0, c[0];\n" "ADD R0.x, R0, R0.y;\n" - "MUL R0.y, R0.x, c[9].x;\n" - "MOV R0.x, c[9];\n" - "RSQ R2.x, R5.x;\n" - "RSQ R2.z, R5.z;\n" - "RSQ R2.y, R5.y;\n" "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.z, R0, c[9].y;\n" - "MAD R0.z, R0.y, R0.y, -R0;\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RSQ R0.z, R0.z;\n" - "RCP R0.x, R0.z;\n" - "RCP R0.z, R0.w;\n" - "ADD R0.x, -R0.y, R0;\n" - "MUL R0.x, R0, R0.z;\n" + "MUL R0.y, R0.z, c[9];\n" + "MUL R0.x, R0, c[9];\n" + "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n" + "TEX R1, R0.zwzw, texture[0], 2D;\n" + "MAD R0.y, R0.x, R0.x, -R0;\n" + "RSQ R0.y, R0.y;\n" + "RCP R0.y, R0.y;\n" + "ADD R0.y, -R0.x, R0;\n" + "MOV R0.x, c[9];\n" + "MUL R0.x, R0, c[1];\n" + "MAX R0.z, R1.w, c[9].w;\n" + "RCP R0.z, R0.z;\n" + "MUL R3.xyz, R1, R0.z;\n" + "MAD R4.xyz, R3, c[10].x, -c[10].y;\n" + "RCP R0.x, R0.x;\n" + "MUL R0.x, R0.y, R0;\n" "TEX R0, R0, texture[2], 1D;\n" - "MAD R3.xyz, R0, c[9].x, -R0.w;\n" - "MAD R6.xyz, -R5, c[10].x, c[10].y;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.z, R2.z;\n" - "RCP R2.y, R2.y;\n" - "MAD R2.xyz, R1.w, R2, -R1;\n" - "MUL R2.xyz, R3, R2;\n" - "MAD R4.xyz, R0.w, R1, R2;\n" - "MAD R2.xyz, -R1, R2.w, c[9].z;\n" - "MUL R5.xyz, R2, R3;\n" - "MAD R6.xyz, -R5, R6, R0.w;\n" - "MAD R5.xyz, -R1, R6, R4;\n" - "MAD R2.xyz, -R2, R3, R0.w;\n" + "MAD R2.xyz, R0, c[9].x, -R0.w;\n" + "MAD R4.xyz, R3, R4, c[10].z;\n" + "MUL R5.xyz, R1.w, R2;\n" + "MUL R6.xyz, R5, R4;\n" + "RSQ R2.w, R3.x;\n" + "RCP R4.x, R2.w;\n" + "RSQ R2.w, R3.y;\n" + "RSQ R3.w, R3.z;\n" + "RCP R4.y, R2.w;\n" + "RCP R4.z, R3.w;\n" + "ADD R4.xyz, -R3, R4;\n" + "MUL R6.xyz, R3, R6;\n" + "MUL R4.xyz, R5, R4;\n" + "ADD R3.xyz, -R3, c[9].z;\n" + "MAD R2.xyz, R2, R3, R0.w;\n" "MUL R3.xyz, R0, c[9].x;\n" - "MUL R4.xyz, R1, c[10].x;\n" - "SGE R3.xyz, R3, R0.w;\n" - "ADD R2.w, -R1, c[9].z;\n" - "MUL R6.xyz, R1, R6;\n" + "MAD R5.xyz, R0.w, R1, R6;\n" + "MAD R4.xyz, R0.w, R1, R4;\n" + "ADD R6.xyz, R4, -R5;\n" + "MUL R4.xyz, R1, c[9].y;\n" "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R5, R6;\n" + "MAD R4.xyz, R4, R6, R5;\n" "MAD R4.xyz, -R1, R2, R4;\n" + "SGE R3.xyz, R3, R0.w;\n" "MUL R2.xyz, R1, R2;\n" + "ADD R2.w, -R1, c[9].z;\n" "MAD R2.xyz, R3, R4, R2;\n" "MAD R2.xyz, R0, R2.w, R2;\n" "ADD R0.x, -R0.w, c[9].z;\n" @@ -2060,7 +2064,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD "!!ARBfp1.0\n" "PARAM c[8] = { program.local[0..5],\n" " { 2, 4, 1, 9.9999997e-006 },\n" - " { 8, 3 } };\n" + " { 16, 12, 3 } };\n" "TEMP R0;\n" "TEMP R1;\n" "TEMP R2;\n" @@ -2072,49 +2076,51 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD "MAD R0.xyz, fragment.position.x, c[2], R0;\n" "ADD R0.xyz, R0, c[4];\n" "RCP R0.z, R0.z;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "MAX R0.w, R1, c[6];\n" - "RCP R2.w, R0.w;\n" - "MUL R5.xyz, R1, R2.w;\n" "MUL R0.xy, R0, R0.z;\n" "MUL R0.zw, R0.xyxy, R0.xyxy;\n" "ADD R0.z, R0, R0.w;\n" "MUL R0.xy, R0, c[0];\n" "ADD R0.x, R0, R0.y;\n" - "MUL R0.y, R0.x, c[6].x;\n" - "MOV R0.x, c[6];\n" - "RSQ R2.x, R5.x;\n" - "RSQ R2.z, R5.z;\n" - "RSQ R2.y, R5.y;\n" "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.z, R0, c[6].y;\n" - "MAD R0.z, R0.y, R0.y, -R0;\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RSQ R0.z, R0.z;\n" - "RCP R0.x, R0.z;\n" - "RCP R0.z, R0.w;\n" - "ADD R0.x, -R0.y, R0;\n" - "MUL R0.x, R0, R0.z;\n" + "MUL R0.y, R0.z, c[6];\n" + "MUL R0.x, R0, c[6];\n" + "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" + "TEX R1, R0.zwzw, texture[0], 2D;\n" + "MAD R0.y, R0.x, R0.x, -R0;\n" + "RSQ R0.y, R0.y;\n" + "RCP R0.y, R0.y;\n" + "ADD R0.y, -R0.x, R0;\n" + "MOV R0.x, c[6];\n" + "MUL R0.x, R0, c[1];\n" + "MAX R0.z, R1.w, c[6].w;\n" + "RCP R0.z, R0.z;\n" + "MUL R3.xyz, R1, R0.z;\n" + "MAD R4.xyz, R3, c[7].x, -c[7].y;\n" + "RCP R0.x, R0.x;\n" + "MUL R0.x, R0.y, R0;\n" "TEX R0, R0, texture[1], 1D;\n" - "MAD R3.xyz, R0, c[6].x, -R0.w;\n" - "MAD R6.xyz, -R5, c[7].x, c[7].y;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.z, R2.z;\n" - "RCP R2.y, R2.y;\n" - "MAD R2.xyz, R1.w, R2, -R1;\n" - "MUL R2.xyz, R3, R2;\n" - "MAD R4.xyz, R0.w, R1, R2;\n" - "MAD R2.xyz, -R1, R2.w, c[6].z;\n" - "MUL R5.xyz, R2, R3;\n" - "MAD R2.xyz, -R2, R3, R0.w;\n" - "MAD R6.xyz, -R5, R6, R0.w;\n" - "MAD R5.xyz, -R1, R6, R4;\n" + "MAD R2.xyz, R0, c[6].x, -R0.w;\n" + "MAD R4.xyz, R3, R4, c[7].z;\n" + "MUL R5.xyz, R1.w, R2;\n" + "MUL R6.xyz, R5, R4;\n" + "RSQ R2.w, R3.x;\n" + "RCP R4.x, R2.w;\n" + "RSQ R2.w, R3.y;\n" + "RSQ R3.w, R3.z;\n" + "RCP R4.y, R2.w;\n" + "RCP R4.z, R3.w;\n" + "ADD R4.xyz, -R3, R4;\n" + "MUL R6.xyz, R3, R6;\n" + "MUL R4.xyz, R5, R4;\n" + "ADD R3.xyz, -R3, c[6].z;\n" + "MAD R2.xyz, R2, R3, R0.w;\n" "MUL R3.xyz, R0, c[6].x;\n" - "MUL R4.xyz, R1, c[7].x;\n" - "MUL R6.xyz, R1, R6;\n" + "MAD R5.xyz, R0.w, R1, R6;\n" + "MAD R4.xyz, R0.w, R1, R4;\n" + "ADD R6.xyz, R4, -R5;\n" + "MUL R4.xyz, R1, c[6].y;\n" "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R5, R6;\n" + "MAD R4.xyz, R4, R6, R5;\n" "MAD R4.xyz, -R1, R2, R4;\n" "MUL R2.xyz, R1, R2;\n" "SGE R3.xyz, R3, R0.w;\n" @@ -2899,11 +2905,12 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SOFTLIGHT = "!!ARBfp1.0\n" - "PARAM c[12] = { program.local[0..7],\n" + "PARAM c[13] = { program.local[0..7],\n" " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n" " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n" " { 3.141593, 0.15915494, 1, 2 },\n" - " { 9.9999997e-006, 8, 3 } };\n" + " { 9.9999997e-006, 4, 16, 12 },\n" + " { 3 } };\n" "TEMP R0;\n" "TEMP R1;\n" "TEMP R2;\n" @@ -2940,41 +2947,43 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO "ADD R0.w, -R0.z, c[10].x;\n" "CMP R0.x, R0, R0.w, R0.z;\n" "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MAX R0.y, R1.w, c[11].x;\n" - "RCP R2.w, R0.y;\n" - "MUL R5.xyz, R1, R2.w;\n" - "RSQ R2.x, R5.x;\n" - "RSQ R2.z, R5.z;\n" - "RSQ R2.y, R5.y;\n" + "CMP R0.x, -R0.y, -R0, R0;\n" + "MAX R0.z, R1.w, c[11].x;\n" + "RCP R2.x, R0.z;\n" + "MUL R3.xyz, R1, R2.x;\n" + "MAD R4.xyz, R3, c[11].z, -c[11].w;\n" "ADD R0.x, R0, c[0];\n" "MUL R0.x, R0, c[10].y;\n" "FLR R0.y, R0.x;\n" "ADD R0.x, R0, -R0.y;\n" "TEX R0, R0, texture[2], 1D;\n" - "MAD R3.xyz, R0, c[10].w, -R0.w;\n" - "MAD R6.xyz, -R5, c[11].y, c[11].z;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.z, R2.z;\n" - "RCP R2.y, R2.y;\n" - "MAD R2.xyz, R1.w, R2, -R1;\n" - "MUL R2.xyz, R3, R2;\n" - "MAD R4.xyz, R0.w, R1, R2;\n" - "MAD R2.xyz, -R1, R2.w, c[10].z;\n" - "MUL R5.xyz, R2, R3;\n" - "MAD R6.xyz, -R5, R6, R0.w;\n" - "MAD R5.xyz, -R1, R6, R4;\n" - "MAD R2.xyz, -R2, R3, R0.w;\n" + "MAD R2.xyz, R0, c[10].w, -R0.w;\n" + "MAD R4.xyz, R3, R4, c[12].x;\n" + "MUL R5.xyz, R1.w, R2;\n" + "MUL R6.xyz, R5, R4;\n" + "RSQ R2.w, R3.x;\n" + "RCP R4.x, R2.w;\n" + "RSQ R2.w, R3.y;\n" + "RSQ R3.w, R3.z;\n" + "RCP R4.y, R2.w;\n" + "RCP R4.z, R3.w;\n" + "ADD R4.xyz, -R3, R4;\n" + "MUL R6.xyz, R3, R6;\n" + "MUL R4.xyz, R5, R4;\n" + "ADD R3.xyz, -R3, c[10].z;\n" + "MAD R2.xyz, R2, R3, R0.w;\n" "MUL R3.xyz, R0, c[10].w;\n" + "MAD R5.xyz, R0.w, R1, R6;\n" + "MAD R4.xyz, R0.w, R1, R4;\n" + "ADD R6.xyz, R4, -R5;\n" "MUL R4.xyz, R1, c[11].y;\n" - "SGE R3.xyz, R3, R0.w;\n" - "ADD R2.w, -R1, c[10].z;\n" - "MUL R6.xyz, R1, R6;\n" "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R5, R6;\n" + "MAD R4.xyz, R4, R6, R5;\n" "MAD R4.xyz, -R1, R2, R4;\n" + "SGE R3.xyz, R3, R0.w;\n" "MUL R2.xyz, R1, R2;\n" + "ADD R2.w, -R1, c[10].z;\n" "MAD R2.xyz, R3, R4, R2;\n" "MAD R2.xyz, R0, R2.w, R2;\n" "ADD R0.x, -R0.w, c[10].z;\n" @@ -3682,11 +3691,12 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SOFTLIGHT_NOMASK = "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..4],\n" + "PARAM c[10] = { program.local[0..4],\n" " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n" " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n" " { 3.141593, 0.15915494, 1, 2 },\n" - " { 9.9999997e-006, 8, 3 } };\n" + " { 9.9999997e-006, 4, 16, 12 },\n" + " { 3 } };\n" "TEMP R0;\n" "TEMP R1;\n" "TEMP R2;\n" @@ -3723,37 +3733,39 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO "ADD R0.w, -R0.z, c[7].x;\n" "CMP R0.x, R0, R0.w, R0.z;\n" "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MAX R0.y, R1.w, c[8].x;\n" - "RCP R2.w, R0.y;\n" - "MUL R5.xyz, R1, R2.w;\n" - "RSQ R2.x, R5.x;\n" - "RSQ R2.z, R5.z;\n" - "RSQ R2.y, R5.y;\n" + "CMP R0.x, -R0.y, -R0, R0;\n" + "MAX R0.z, R1.w, c[8].x;\n" + "RCP R2.x, R0.z;\n" + "MUL R3.xyz, R1, R2.x;\n" + "MAD R4.xyz, R3, c[8].z, -c[8].w;\n" "ADD R0.x, R0, c[0];\n" "MUL R0.x, R0, c[7].y;\n" "FLR R0.y, R0.x;\n" "ADD R0.x, R0, -R0.y;\n" "TEX R0, R0, texture[1], 1D;\n" - "MAD R3.xyz, R0, c[7].w, -R0.w;\n" - "MAD R6.xyz, -R5, c[8].y, c[8].z;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.z, R2.z;\n" - "RCP R2.y, R2.y;\n" - "MAD R2.xyz, R1.w, R2, -R1;\n" - "MUL R2.xyz, R3, R2;\n" - "MAD R4.xyz, R0.w, R1, R2;\n" - "MAD R2.xyz, -R1, R2.w, c[7].z;\n" - "MUL R5.xyz, R2, R3;\n" - "MAD R2.xyz, -R2, R3, R0.w;\n" - "MAD R6.xyz, -R5, R6, R0.w;\n" - "MAD R5.xyz, -R1, R6, R4;\n" + "MAD R2.xyz, R0, c[7].w, -R0.w;\n" + "MAD R4.xyz, R3, R4, c[9].x;\n" + "MUL R5.xyz, R1.w, R2;\n" + "MUL R6.xyz, R5, R4;\n" + "RSQ R2.w, R3.x;\n" + "RCP R4.x, R2.w;\n" + "RSQ R2.w, R3.y;\n" + "RSQ R3.w, R3.z;\n" + "RCP R4.y, R2.w;\n" + "RCP R4.z, R3.w;\n" + "ADD R4.xyz, -R3, R4;\n" + "MUL R6.xyz, R3, R6;\n" + "MUL R4.xyz, R5, R4;\n" + "ADD R3.xyz, -R3, c[7].z;\n" + "MAD R2.xyz, R2, R3, R0.w;\n" "MUL R3.xyz, R0, c[7].w;\n" + "MAD R5.xyz, R0.w, R1, R6;\n" + "MAD R4.xyz, R0.w, R1, R4;\n" + "ADD R6.xyz, R4, -R5;\n" "MUL R4.xyz, R1, c[8].y;\n" - "MUL R6.xyz, R1, R6;\n" "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R5, R6;\n" + "MAD R4.xyz, R4, R6, R5;\n" "MAD R4.xyz, -R1, R2, R4;\n" "MUL R2.xyz, R1, R2;\n" "SGE R3.xyz, R3, R0.w;\n" @@ -4356,8 +4368,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SOFTLIGHT = "!!ARBfp1.0\n" "PARAM c[10] = { program.local[0..7],\n" - " { 1, 2, 9.9999997e-006, 8 },\n" - " { 3 } };\n" + " { 1, 2, 9.9999997e-006, 4 },\n" + " { 16, 12, 3 } };\n" "TEMP R0;\n" "TEMP R1;\n" "TEMP R2;\n" @@ -4365,13 +4377,6 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD "TEMP R4;\n" "TEMP R5;\n" "TEMP R6;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R1, R0, texture[0], 2D;\n" - "MAX R0.w, R1, c[8].z;\n" - "RCP R2.w, R0.w;\n" - "MUL R2.xyz, R1, R2.w;\n" - "RSQ R0.w, R2.x;\n" - "MUL R5.xyz, -R2, c[8].w;\n" "MUL R0.xyz, fragment.position.y, c[2];\n" "MAD R0.xyz, fragment.position.x, c[1], R0;\n" "ADD R0.xyz, R0, c[3];\n" @@ -4379,32 +4384,40 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD "MUL R0.xy, R0, R0.z;\n" "MUL R0.xy, R0, c[0];\n" "ADD R0.x, R0, R0.y;\n" - "RSQ R0.z, R2.y;\n" - "RSQ R0.y, R2.z;\n" - "MAD R2.xyz, -R1, R2.w, c[8].x;\n" - "RCP R3.x, R0.w;\n" - "RCP R3.y, R0.z;\n" - "RCP R3.z, R0.y;\n" + "MUL R1.xy, fragment.position, c[5];\n" + "TEX R1, R1, texture[0], 2D;\n" + "MAX R0.z, R1.w, c[8];\n" + "RCP R0.z, R0.z;\n" + "MUL R3.xyz, R1, R0.z;\n" + "MAD R2.xyz, R3, c[9].x, -c[9].y;\n" "MUL R0.x, R0, c[0].z;\n" "TEX R0, R0, texture[2], 1D;\n" - "MAD R4.xyz, R1.w, R3, -R1;\n" - "MAD R3.xyz, R0, c[8].y, -R0.w;\n" - "MUL R4.xyz, R3, R4;\n" - "ADD R6.xyz, R5, c[9].x;\n" - "MUL R5.xyz, R2, R3;\n" - "MAD R2.xyz, -R2, R3, R0.w;\n" + "MAD R4.xyz, R3, R2, c[9].z;\n" + "MAD R2.xyz, R0, c[8].y, -R0.w;\n" + "MUL R5.xyz, R1.w, R2;\n" + "MUL R6.xyz, R5, R4;\n" + "RSQ R2.w, R3.x;\n" + "RCP R4.x, R2.w;\n" + "RSQ R2.w, R3.y;\n" + "RSQ R3.w, R3.z;\n" + "RCP R4.y, R2.w;\n" + "RCP R4.z, R3.w;\n" + "ADD R4.xyz, -R3, R4;\n" + "MUL R6.xyz, R3, R6;\n" + "MUL R4.xyz, R5, R4;\n" + "ADD R3.xyz, -R3, c[8].x;\n" + "MAD R2.xyz, R2, R3, R0.w;\n" "MUL R3.xyz, R0, c[8].y;\n" - "MAD R6.xyz, -R5, R6, R0.w;\n" + "MAD R5.xyz, R0.w, R1, R6;\n" "MAD R4.xyz, R0.w, R1, R4;\n" - "MAD R5.xyz, -R1, R6, R4;\n" + "ADD R6.xyz, R4, -R5;\n" "MUL R4.xyz, R1, c[8].w;\n" - "SGE R3.xyz, R3, R0.w;\n" - "ADD R2.w, -R1, c[8].x;\n" - "MUL R6.xyz, R1, R6;\n" "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R5, R6;\n" + "MAD R4.xyz, R4, R6, R5;\n" "MAD R4.xyz, -R1, R2, R4;\n" + "SGE R3.xyz, R3, R0.w;\n" "MUL R2.xyz, R1, R2;\n" + "ADD R2.w, -R1, c[8].x;\n" "MAD R2.xyz, R3, R4, R2;\n" "MAD R2.xyz, R0, R2.w, R2;\n" "ADD R0.x, -R0.w, c[8];\n" @@ -4815,8 +4828,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SOFTLIGHT_NOMASK = "!!ARBfp1.0\n" "PARAM c[7] = { program.local[0..4],\n" - " { 1, 2, 9.9999997e-006, 8 },\n" - " { 3 } };\n" + " { 1, 2, 9.9999997e-006, 4 },\n" + " { 16, 12, 3 } };\n" "TEMP R0;\n" "TEMP R1;\n" "TEMP R2;\n" @@ -4824,13 +4837,6 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD "TEMP R4;\n" "TEMP R5;\n" "TEMP R6;\n" - "MUL R0.xy, fragment.position, c[4];\n" - "TEX R1, R0, texture[0], 2D;\n" - "MAX R0.w, R1, c[5].z;\n" - "RCP R2.w, R0.w;\n" - "MUL R2.xyz, R1, R2.w;\n" - "RSQ R0.w, R2.x;\n" - "MUL R5.xyz, -R2, c[5].w;\n" "MUL R0.xyz, fragment.position.y, c[2];\n" "MAD R0.xyz, fragment.position.x, c[1], R0;\n" "ADD R0.xyz, R0, c[3];\n" @@ -4838,28 +4844,36 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD "MUL R0.xy, R0, R0.z;\n" "MUL R0.xy, R0, c[0];\n" "ADD R0.x, R0, R0.y;\n" - "RSQ R0.z, R2.y;\n" - "RSQ R0.y, R2.z;\n" - "MAD R2.xyz, -R1, R2.w, c[5].x;\n" - "RCP R3.x, R0.w;\n" - "RCP R3.y, R0.z;\n" - "RCP R3.z, R0.y;\n" + "MUL R1.xy, fragment.position, c[4];\n" + "TEX R1, R1, texture[0], 2D;\n" + "MAX R0.z, R1.w, c[5];\n" + "RCP R0.z, R0.z;\n" + "MUL R3.xyz, R1, R0.z;\n" + "MAD R2.xyz, R3, c[6].x, -c[6].y;\n" "MUL R0.x, R0, c[0].z;\n" "TEX R0, R0, texture[1], 1D;\n" - "MAD R4.xyz, R1.w, R3, -R1;\n" - "MAD R3.xyz, R0, c[5].y, -R0.w;\n" - "MUL R4.xyz, R3, R4;\n" - "ADD R6.xyz, R5, c[6].x;\n" - "MUL R5.xyz, R2, R3;\n" - "MAD R2.xyz, -R2, R3, R0.w;\n" + "MAD R4.xyz, R3, R2, c[6].z;\n" + "MAD R2.xyz, R0, c[5].y, -R0.w;\n" + "MUL R5.xyz, R1.w, R2;\n" + "MUL R6.xyz, R5, R4;\n" + "RSQ R2.w, R3.x;\n" + "RCP R4.x, R2.w;\n" + "RSQ R2.w, R3.y;\n" + "RSQ R3.w, R3.z;\n" + "RCP R4.y, R2.w;\n" + "RCP R4.z, R3.w;\n" + "ADD R4.xyz, -R3, R4;\n" + "MUL R6.xyz, R3, R6;\n" + "MUL R4.xyz, R5, R4;\n" + "ADD R3.xyz, -R3, c[5].x;\n" + "MAD R2.xyz, R2, R3, R0.w;\n" "MUL R3.xyz, R0, c[5].y;\n" - "MAD R6.xyz, -R5, R6, R0.w;\n" + "MAD R5.xyz, R0.w, R1, R6;\n" "MAD R4.xyz, R0.w, R1, R4;\n" - "MAD R5.xyz, -R1, R6, R4;\n" + "ADD R6.xyz, R4, -R5;\n" "MUL R4.xyz, R1, c[5].w;\n" - "MUL R6.xyz, R1, R6;\n" "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R5, R6;\n" + "MAD R4.xyz, R4, R6, R5;\n" "MAD R4.xyz, -R1, R2, R4;\n" "MUL R2.xyz, R1, R2;\n" "SGE R3.xyz, R3, R0.w;\n" @@ -5333,8 +5347,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SOFTLIGHT = "!!ARBfp1.0\n" "PARAM c[10] = { program.local[0..7],\n" - " { 1, 2, 9.9999997e-006, 8 },\n" - " { 3 } };\n" + " { 1, 2, 9.9999997e-006, 4 },\n" + " { 16, 12, 3 } };\n" "TEMP R0;\n" "TEMP R1;\n" "TEMP R2;\n" @@ -5342,44 +5356,45 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO "TEMP R4;\n" "TEMP R5;\n" "TEMP R6;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R1, R0, texture[0], 2D;\n" - "MAX R0.x, R1.w, c[8].z;\n" - "RCP R2.w, R0.x;\n" - "MUL R2.xyz, R1, R2.w;\n" - "RSQ R0.w, R2.x;\n" - "RCP R3.x, R0.w;\n" - "RSQ R0.w, R2.y;\n" - "MUL R5.xyz, -R2, c[8].w;\n" "MUL R0.xyz, fragment.position.y, c[2];\n" + "MUL R1.xy, fragment.position, c[5];\n" + "TEX R1, R1, texture[0], 2D;\n" "MAD R0.xyz, fragment.position.x, c[1], R0;\n" "ADD R0.xyz, R0, c[3];\n" "RCP R0.z, R0.z;\n" "MUL R0.xy, R0, R0.z;\n" - "RSQ R0.z, R2.z;\n" - "MAD R2.xyz, -R1, R2.w, c[8].x;\n" - "RCP R3.y, R0.w;\n" - "RCP R3.z, R0.z;\n" + "MAX R0.w, R1, c[8].z;\n" + "RCP R0.w, R0.w;\n" + "MUL R3.xyz, R1, R0.w;\n" + "MAD R2.xyz, R3, c[9].x, -c[9].y;\n" "MUL R0.xy, R0, c[0];\n" "TEX R0, R0, texture[2], 2D;\n" - "MAD R4.xyz, R1.w, R3, -R1;\n" - "MAD R3.xyz, R0, c[8].y, -R0.w;\n" - "MUL R4.xyz, R3, R4;\n" - "ADD R6.xyz, R5, c[9].x;\n" - "MUL R5.xyz, R2, R3;\n" - "MAD R2.xyz, -R2, R3, R0.w;\n" + "MAD R4.xyz, R3, R2, c[9].z;\n" + "MAD R2.xyz, R0, c[8].y, -R0.w;\n" + "MUL R5.xyz, R1.w, R2;\n" + "MUL R6.xyz, R5, R4;\n" + "RSQ R2.w, R3.x;\n" + "RCP R4.x, R2.w;\n" + "RSQ R2.w, R3.y;\n" + "RSQ R3.w, R3.z;\n" + "RCP R4.y, R2.w;\n" + "RCP R4.z, R3.w;\n" + "ADD R4.xyz, -R3, R4;\n" + "MUL R6.xyz, R3, R6;\n" + "MUL R4.xyz, R5, R4;\n" + "ADD R3.xyz, -R3, c[8].x;\n" + "MAD R2.xyz, R2, R3, R0.w;\n" "MUL R3.xyz, R0, c[8].y;\n" - "MAD R6.xyz, -R5, R6, R0.w;\n" + "MAD R5.xyz, R0.w, R1, R6;\n" "MAD R4.xyz, R0.w, R1, R4;\n" - "MAD R5.xyz, -R1, R6, R4;\n" + "ADD R6.xyz, R4, -R5;\n" "MUL R4.xyz, R1, c[8].w;\n" - "SGE R3.xyz, R3, R0.w;\n" - "ADD R2.w, -R1, c[8].x;\n" - "MUL R6.xyz, R1, R6;\n" "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R5, R6;\n" + "MAD R4.xyz, R4, R6, R5;\n" "MAD R4.xyz, -R1, R2, R4;\n" + "SGE R3.xyz, R3, R0.w;\n" "MUL R2.xyz, R1, R2;\n" + "ADD R2.w, -R1, c[8].x;\n" "MAD R2.xyz, R3, R4, R2;\n" "MAD R2.xyz, R0, R2.w, R2;\n" "ADD R0.x, -R0.w, c[8];\n" @@ -5768,8 +5783,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SOFTLIGHT_NOMASK = "!!ARBfp1.0\n" "PARAM c[7] = { program.local[0..4],\n" - " { 1, 2, 9.9999997e-006, 8 },\n" - " { 3 } };\n" + " { 1, 2, 9.9999997e-006, 4 },\n" + " { 16, 12, 3 } };\n" "TEMP R0;\n" "TEMP R1;\n" "TEMP R2;\n" @@ -5777,40 +5792,41 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO "TEMP R4;\n" "TEMP R5;\n" "TEMP R6;\n" - "MUL R0.xy, fragment.position, c[4];\n" - "TEX R1, R0, texture[0], 2D;\n" - "MAX R0.x, R1.w, c[5].z;\n" - "RCP R2.w, R0.x;\n" - "MUL R2.xyz, R1, R2.w;\n" - "RSQ R0.w, R2.x;\n" - "RCP R3.x, R0.w;\n" - "RSQ R0.w, R2.y;\n" - "MUL R5.xyz, -R2, c[5].w;\n" "MUL R0.xyz, fragment.position.y, c[2];\n" + "MUL R1.xy, fragment.position, c[4];\n" + "TEX R1, R1, texture[0], 2D;\n" "MAD R0.xyz, fragment.position.x, c[1], R0;\n" "ADD R0.xyz, R0, c[3];\n" "RCP R0.z, R0.z;\n" "MUL R0.xy, R0, R0.z;\n" - "RSQ R0.z, R2.z;\n" - "MAD R2.xyz, -R1, R2.w, c[5].x;\n" - "RCP R3.y, R0.w;\n" - "RCP R3.z, R0.z;\n" + "MAX R0.w, R1, c[5].z;\n" + "RCP R0.w, R0.w;\n" + "MUL R3.xyz, R1, R0.w;\n" + "MAD R2.xyz, R3, c[6].x, -c[6].y;\n" "MUL R0.xy, R0, c[0];\n" "TEX R0, R0, texture[1], 2D;\n" - "MAD R4.xyz, R1.w, R3, -R1;\n" - "MAD R3.xyz, R0, c[5].y, -R0.w;\n" - "MUL R4.xyz, R3, R4;\n" - "ADD R6.xyz, R5, c[6].x;\n" - "MUL R5.xyz, R2, R3;\n" - "MAD R2.xyz, -R2, R3, R0.w;\n" + "MAD R4.xyz, R3, R2, c[6].z;\n" + "MAD R2.xyz, R0, c[5].y, -R0.w;\n" + "MUL R5.xyz, R1.w, R2;\n" + "MUL R6.xyz, R5, R4;\n" + "RSQ R2.w, R3.x;\n" + "RCP R4.x, R2.w;\n" + "RSQ R2.w, R3.y;\n" + "RSQ R3.w, R3.z;\n" + "RCP R4.y, R2.w;\n" + "RCP R4.z, R3.w;\n" + "ADD R4.xyz, -R3, R4;\n" + "MUL R6.xyz, R3, R6;\n" + "MUL R4.xyz, R5, R4;\n" + "ADD R3.xyz, -R3, c[5].x;\n" + "MAD R2.xyz, R2, R3, R0.w;\n" "MUL R3.xyz, R0, c[5].y;\n" - "MAD R6.xyz, -R5, R6, R0.w;\n" + "MAD R5.xyz, R0.w, R1, R6;\n" "MAD R4.xyz, R0.w, R1, R4;\n" - "MAD R5.xyz, -R1, R6, R4;\n" + "ADD R6.xyz, R4, -R5;\n" "MUL R4.xyz, R1, c[5].w;\n" - "MUL R6.xyz, R1, R6;\n" "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R5, R6;\n" + "MAD R4.xyz, R4, R6, R5;\n" "MAD R4.xyz, -R1, R2, R4;\n" "MUL R2.xyz, R1, R2;\n" "SGE R3.xyz, R3, R0.w;\n" @@ -6295,8 +6311,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SOFTLIGHT = "!!ARBfp1.0\n" "PARAM c[10] = { program.local[0..7],\n" - " { 1, 2, 9.9999997e-006, 8 },\n" - " { 3 } };\n" + " { 1, 2, 9.9999997e-006, 4 },\n" + " { 16, 12, 3 } };\n" "TEMP R0;\n" "TEMP R1;\n" "TEMP R2;\n" @@ -6304,46 +6320,47 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO "TEMP R4;\n" "TEMP R5;\n" "TEMP R6;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MAX R1.w, R0, c[8].z;\n" - "RCP R2.w, R1.w;\n" - "MUL R2.xyz, R0, R2.w;\n" - "RSQ R1.w, R2.x;\n" - "MUL R5.xyz, -R2, c[8].w;\n" - "MUL R1.xyz, fragment.position.y, c[2];\n" - "MAD R1.xyz, fragment.position.x, c[1], R1;\n" - "ADD R1.xyz, R1, c[3];\n" + "MUL R0.xyz, fragment.position.y, c[2];\n" + "MAD R0.xyz, fragment.position.x, c[1], R0;\n" + "ADD R1.xyz, R0, c[3];\n" "RCP R1.z, R1.z;\n" "MUL R1.xy, R1, R1.z;\n" "MUL R1.xy, R1, c[0];\n" "TEX R1.x, R1, texture[2], 2D;\n" - "RSQ R1.z, R2.y;\n" - "RSQ R1.y, R2.z;\n" - "MAD R2.xyz, -R0, R2.w, c[8].x;\n" - "RCP R3.x, R1.w;\n" - "RCP R3.y, R1.z;\n" - "RCP R3.z, R1.y;\n" + "MUL R0.xy, fragment.position, c[5];\n" + "TEX R0, R0, texture[0], 2D;\n" + "MAX R1.z, R0.w, c[8];\n" + "RCP R1.z, R1.z;\n" + "MUL R3.xyz, R0, R1.z;\n" + "MAD R2.xyz, R3, c[9].x, -c[9].y;\n" "ADD R1.x, -R1, c[8];\n" "MUL R1, fragment.color.primary, R1.x;\n" - "MAD R4.xyz, R0.w, R3, -R0;\n" - "MAD R3.xyz, R1, c[8].y, -R1.w;\n" - "MUL R4.xyz, R3, R4;\n" - "ADD R6.xyz, R5, c[9].x;\n" - "MUL R5.xyz, R2, R3;\n" - "MAD R2.xyz, -R2, R3, R1.w;\n" + "MAD R4.xyz, R3, R2, c[9].z;\n" + "MAD R2.xyz, R1, c[8].y, -R1.w;\n" + "MUL R5.xyz, R0.w, R2;\n" + "MUL R6.xyz, R5, R4;\n" + "RSQ R2.w, R3.x;\n" + "RCP R4.x, R2.w;\n" + "RSQ R2.w, R3.y;\n" + "RSQ R3.w, R3.z;\n" + "RCP R4.y, R2.w;\n" + "RCP R4.z, R3.w;\n" + "ADD R4.xyz, -R3, R4;\n" + "MUL R6.xyz, R3, R6;\n" + "MUL R4.xyz, R5, R4;\n" + "ADD R3.xyz, -R3, c[8].x;\n" + "MAD R2.xyz, R2, R3, R1.w;\n" "MUL R3.xyz, R1, c[8].y;\n" - "MAD R6.xyz, -R5, R6, R1.w;\n" + "MAD R5.xyz, R1.w, R0, R6;\n" "MAD R4.xyz, R1.w, R0, R4;\n" - "MAD R5.xyz, -R0, R6, R4;\n" + "ADD R6.xyz, R4, -R5;\n" "MUL R4.xyz, R0, c[8].w;\n" - "SGE R3.xyz, R3, R1.w;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MUL R6.xyz, R0, R6;\n" "SGE R4.xyz, R4, R0.w;\n" - "MAD R4.xyz, R4, R5, R6;\n" + "MAD R4.xyz, R4, R6, R5;\n" "MAD R4.xyz, -R0, R2, R4;\n" + "SGE R3.xyz, R3, R1.w;\n" "MUL R2.xyz, R0, R2;\n" + "ADD R2.w, -R0, c[8].x;\n" "MAD R2.xyz, R3, R4, R2;\n" "MAD R2.xyz, R1, R2.w, R2;\n" "ADD R1.x, -R1.w, c[8];\n" @@ -6755,8 +6772,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SOFTLIGHT_NOMASK = "!!ARBfp1.0\n" "PARAM c[7] = { program.local[0..4],\n" - " { 1, 2, 9.9999997e-006, 8 },\n" - " { 3 } };\n" + " { 1, 2, 9.9999997e-006, 4 },\n" + " { 16, 12, 3 } };\n" "TEMP R0;\n" "TEMP R1;\n" "TEMP R2;\n" @@ -6764,42 +6781,43 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO "TEMP R4;\n" "TEMP R5;\n" "TEMP R6;\n" - "MUL R0.xy, fragment.position, c[4];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MAX R1.w, R0, c[5].z;\n" - "RCP R2.w, R1.w;\n" - "MUL R2.xyz, R0, R2.w;\n" - "RSQ R1.w, R2.x;\n" - "MUL R5.xyz, -R2, c[5].w;\n" - "MUL R1.xyz, fragment.position.y, c[2];\n" - "MAD R1.xyz, fragment.position.x, c[1], R1;\n" - "ADD R1.xyz, R1, c[3];\n" + "MUL R0.xyz, fragment.position.y, c[2];\n" + "MAD R0.xyz, fragment.position.x, c[1], R0;\n" + "ADD R1.xyz, R0, c[3];\n" "RCP R1.z, R1.z;\n" "MUL R1.xy, R1, R1.z;\n" "MUL R1.xy, R1, c[0];\n" "TEX R1.x, R1, texture[1], 2D;\n" - "RSQ R1.z, R2.y;\n" - "RSQ R1.y, R2.z;\n" - "MAD R2.xyz, -R0, R2.w, c[5].x;\n" - "RCP R3.x, R1.w;\n" - "RCP R3.y, R1.z;\n" - "RCP R3.z, R1.y;\n" + "MUL R0.xy, fragment.position, c[4];\n" + "TEX R0, R0, texture[0], 2D;\n" + "MAX R1.z, R0.w, c[5];\n" + "RCP R1.z, R1.z;\n" + "MUL R3.xyz, R0, R1.z;\n" + "MAD R2.xyz, R3, c[6].x, -c[6].y;\n" "ADD R1.x, -R1, c[5];\n" "MUL R1, fragment.color.primary, R1.x;\n" - "MAD R4.xyz, R0.w, R3, -R0;\n" - "MAD R3.xyz, R1, c[5].y, -R1.w;\n" - "MUL R4.xyz, R3, R4;\n" - "ADD R6.xyz, R5, c[6].x;\n" - "MUL R5.xyz, R2, R3;\n" - "MAD R2.xyz, -R2, R3, R1.w;\n" + "MAD R4.xyz, R3, R2, c[6].z;\n" + "MAD R2.xyz, R1, c[5].y, -R1.w;\n" + "MUL R5.xyz, R0.w, R2;\n" + "MUL R6.xyz, R5, R4;\n" + "RSQ R2.w, R3.x;\n" + "RCP R4.x, R2.w;\n" + "RSQ R2.w, R3.y;\n" + "RSQ R3.w, R3.z;\n" + "RCP R4.y, R2.w;\n" + "RCP R4.z, R3.w;\n" + "ADD R4.xyz, -R3, R4;\n" + "MUL R6.xyz, R3, R6;\n" + "MUL R4.xyz, R5, R4;\n" + "ADD R3.xyz, -R3, c[5].x;\n" + "MAD R2.xyz, R2, R3, R1.w;\n" "MUL R3.xyz, R1, c[5].y;\n" - "MAD R6.xyz, -R5, R6, R1.w;\n" + "MAD R5.xyz, R1.w, R0, R6;\n" "MAD R4.xyz, R1.w, R0, R4;\n" - "MAD R5.xyz, -R0, R6, R4;\n" + "ADD R6.xyz, R4, -R5;\n" "MUL R4.xyz, R0, c[5].w;\n" - "MUL R6.xyz, R0, R6;\n" "SGE R4.xyz, R4, R0.w;\n" - "MAD R4.xyz, R4, R5, R6;\n" + "MAD R4.xyz, R4, R6, R5;\n" "MAD R4.xyz, -R0, R2, R4;\n" "MUL R2.xyz, R0, R2;\n" "SGE R3.xyz, R3, R1.w;\n" diff --git a/src/plugins/accessible/widgets/simplewidgets.cpp b/src/plugins/accessible/widgets/simplewidgets.cpp index aa51759..87d81f0 100644 --- a/src/plugins/accessible/widgets/simplewidgets.cpp +++ b/src/plugins/accessible/widgets/simplewidgets.cpp @@ -256,9 +256,9 @@ QString QAccessibleButton::localizedName(int actionIndex) QStringList QAccessibleButton::keyBindings(int actionIndex) { switch (actionIndex) { -#ifdef QT_NO_SHORTCUT +#ifndef QT_NO_SHORTCUT case 0: - return button()->shortcut().toString(); + return QStringList() << button()->shortcut().toString(); #endif default: return QStringList(); @@ -602,6 +602,44 @@ int QAccessibleDisplay::navigate(RelationFlag rel, int entry, QAccessibleInterfa return QAccessibleWidgetEx::navigate(rel, entry, target); } +/*! \reimp */ +QString QAccessibleDisplay::imageDescription() +{ + return widget()->toolTip(); +} + +/*! \reimp */ +QSize QAccessibleDisplay::imageSize() +{ + QLabel *label = qobject_cast<QLabel *>(widget()); + if (!label) + return QSize(); + const QPixmap *pixmap = label->pixmap(); + if (!pixmap) + return QSize(); + return pixmap->size(); +} + +/*! \reimp */ +QRect QAccessibleDisplay::imagePosition(QAccessible2::CoordinateType coordType) +{ + QLabel *label = qobject_cast<QLabel *>(widget()); + if (!label) + return QRect(); + const QPixmap *pixmap = label->pixmap(); + if (!pixmap) + return QRect(); + + switch (coordType) { + case QAccessible2::RelativeToScreen: + return QRect(label->mapToGlobal(label->pos()), label->size()); + case QAccessible2::RelativeToParent: + return label->geometry(); + } + + return QRect(); +} + #ifndef QT_NO_LINEEDIT /*! \class QAccessibleLineEdit diff --git a/src/plugins/accessible/widgets/simplewidgets.h b/src/plugins/accessible/widgets/simplewidgets.h index 0c1cf5e..5182bdd 100644 --- a/src/plugins/accessible/widgets/simplewidgets.h +++ b/src/plugins/accessible/widgets/simplewidgets.h @@ -111,7 +111,7 @@ protected: }; #endif // QT_NO_TOOLBUTTON -class QAccessibleDisplay : public QAccessibleWidgetEx +class QAccessibleDisplay : public QAccessibleWidgetEx, public QAccessibleImageInterface { Q_ACCESSIBLE_OBJECT public: @@ -122,6 +122,11 @@ public: Relation relationTo(int child, const QAccessibleInterface *other, int otherChild) const; int navigate(RelationFlag, int entry, QAccessibleInterface **target) const; + + // QAccessibleImageInterface + QString imageDescription(); + QSize imageSize(); + QRect imagePosition(QAccessible2::CoordinateType coordType); }; #ifndef QT_NO_LINEEDIT diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp index dd6b0d3..c86af73 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -68,9 +68,11 @@ public: }; enum CompositionModeStatus { - PorterDuff_None = 0x0, - PorterDuff_SupportedBlits = 0x1, - PorterDuff_SupportedPrimitives = 0x2 + PorterDuff_None = 0x00, + PorterDuff_SupportedBlits = 0x01, + PorterDuff_SupportedPrimitives = 0x02, + PorterDuff_SupportedOpaquePrimitives = 0x04, + PorterDuff_Dirty = 0x10 }; enum ClipType { @@ -95,6 +97,7 @@ public: inline void unlock(); static inline void unlock(QDirectFBPaintDevice *device); + inline bool testCompositionMode(const QPen *pen, const QBrush *brush, const QColor *color = 0) const; inline bool isSimpleBrush(const QBrush &brush) const; void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos); @@ -404,11 +407,11 @@ void QDirectFBPaintEngine::drawRects(const QRect *rects, int rectCount) if (brush.style() == Qt::NoBrush && pen.style() == Qt::NoPen) return; - if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives) - || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) + if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) || !d->simplePen || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip - || !d->isSimpleBrush(brush)) { + || !d->isSimpleBrush(brush) + || !d->testCompositionMode(&pen, &brush)) { RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG()); d->lock(); QRasterPaintEngine::drawRects(rects, rectCount); @@ -434,11 +437,11 @@ void QDirectFBPaintEngine::drawRects(const QRectF *rects, int rectCount) if (brush.style() == Qt::NoBrush && pen.style() == Qt::NoPen) return; - if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives) - || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) + if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) || !d->simplePen || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip - || !d->isSimpleBrush(brush)) { + || !d->isSimpleBrush(brush) + || !d->testCompositionMode(&pen, &brush)) { RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG()); d->lock(); QRasterPaintEngine::drawRects(rects, rectCount); @@ -460,16 +463,16 @@ void QDirectFBPaintEngine::drawLines(const QLine *lines, int lineCount) { Q_D(QDirectFBPaintEngine); - if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives) - || !d->simplePen - || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) { + const QPen &pen = state()->pen; + if (!d->simplePen + || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip + || !d->testCompositionMode(&pen, 0)) { RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG()); d->lock(); QRasterPaintEngine::drawLines(lines, lineCount); return; } - const QPen &pen = state()->pen; if (pen.style() != Qt::NoPen) { d->setDFBColor(pen.color()); CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawLines<QLine>)(lines, lineCount, state()->matrix, d->surface)); @@ -480,16 +483,16 @@ void QDirectFBPaintEngine::drawLines(const QLineF *lines, int lineCount) { Q_D(QDirectFBPaintEngine); - if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives) - || !d->simplePen - || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) { + const QPen &pen = state()->pen; + if (!d->simplePen + || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip + || !d->testCompositionMode(&pen, 0)) { RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG()); d->lock(); QRasterPaintEngine::drawLines(lines, lineCount); return; } - const QPen &pen = state()->pen; if (pen.style() != Qt::NoPen) { d->setDFBColor(pen.color()); CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawLines<QLineF>)(lines, lineCount, state()->matrix, d->surface)); @@ -714,8 +717,8 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) if (d->clipType != QDirectFBPaintEnginePrivate::ComplexClip) { switch (brush.style()) { case Qt::SolidPattern: { - if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives) - || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)) { + if (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported + || !d->testCompositionMode(0, &brush)) { break; } const QColor color = brush.color(); @@ -753,9 +756,9 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QColor &color) if (!color.isValid()) return; Q_D(QDirectFBPaintEngine); - if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives) - || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) - || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) { + if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported) + || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip + || !d->testCompositionMode(0, 0, &color)) { RASTERFALLBACK(FILL_RECT, rect, color, VOID_ARG()); d->lock(); QRasterPaintEngine::fillRect(rect, color); @@ -815,6 +818,36 @@ bool QDirectFBPaintEnginePrivate::isSimpleBrush(const QBrush &brush) const return (brush.style() == Qt::NoBrush) || (brush.style() == Qt::SolidPattern && !antialiased); } +bool QDirectFBPaintEnginePrivate::testCompositionMode(const QPen *pen, const QBrush *brush, const QColor *color) const +{ + Q_ASSERT(!pen || pen->style() == Qt::NoPen || pen->style() == Qt::SolidLine); + Q_ASSERT(!brush || brush->style() == Qt::NoBrush || brush->style() == Qt::SolidPattern); + switch (compositionModeStatus & (QDirectFBPaintEnginePrivate::PorterDuff_SupportedOpaquePrimitives + |QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)) { + case QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives: + return true; + case QDirectFBPaintEnginePrivate::PorterDuff_SupportedOpaquePrimitives: + if (pen && pen->style() == Qt::SolidLine && pen->color().alpha() != 255) + return false; + if (brush) { + if (brush->style() == Qt::SolidPattern && brush->color().alpha() != 255) { + return false; + } + } else if (color && color->alpha() != 255) { + return false; + } + return true; + case QDirectFBPaintEnginePrivate::PorterDuff_None: + return false; + default: + // ### PorterDuff_SupportedOpaquePrimitives|PorterDuff_SupportedPrimitives can't be combined + break; + } + Q_ASSERT(0); + return false; +} + + void QDirectFBPaintEnginePrivate::lock() { // We will potentially get a new pointer to the buffer after a @@ -888,6 +921,7 @@ void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode m break; case QPainter::CompositionMode_Source: surface->SetPorterDuff(surface, DSPD_SRC); + compositionModeStatus |= PorterDuff_SupportedOpaquePrimitives; break; case QPainter::CompositionMode_SourceOver: compositionModeStatus |= PorterDuff_SupportedPrimitives; @@ -945,6 +979,9 @@ void QDirectFBPaintEnginePrivate::prepareForBlit(bool alpha) } surface->SetColor(surface, 0xff, 0xff, 0xff, opacity); surface->SetBlittingFlags(surface, blittingFlags); + if (compositionModeStatus & PorterDuff_Dirty) { + setCompositionMode(q->state()->composition_mode); + } } static inline uint ALPHA_MUL(uint x, uint a) @@ -962,6 +999,7 @@ void QDirectFBPaintEnginePrivate::setDFBColor(const QColor &color) surface->SetColor(surface, color.red(), color.green(), color.blue(), alpha); surface->SetPorterDuff(surface, DSPD_NONE); surface->SetDrawingFlags(surface, alpha == 255 ? DSDRAW_NOFX : DSDRAW_BLEND); + compositionModeStatus |= PorterDuff_Dirty; } IDirectFBSurface *QDirectFBPaintEnginePrivate::getSurface(const QImage &img, bool *release) diff --git a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp index c1410a6..1dec9ea 100644 --- a/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp +++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp @@ -271,67 +271,6 @@ int PvrEglScreen::transformation() const #endif -#ifndef QT_NO_QWS_TRANSFORMED - -static const QScreen *parentScreen - (const QScreen *current, const QScreen *lookingFor) -{ - if (!current) - return 0; - switch (current->classId()) { - case QScreen::ProxyClass: - case QScreen::TransformedClass: { - const QScreen *child = - static_cast<const QProxyScreen *>(current)->screen(); - if (child == lookingFor) - return current; - else - return parentScreen(child, lookingFor); - } - // Not reached. - - case QScreen::MultiClass: { - QList<QScreen *> screens = current->subScreens(); - foreach (QScreen *screen, screens) { - if (screen == lookingFor) - return current; - const QScreen *parent = parentScreen(screen, lookingFor); - if (parent) - return parent; - } - } - break; - - default: break; - } - return 0; -} - -int PvrEglScreen::transformation() const -{ - // We need to search for our parent screen, which is assumed to be - // "Transformed". If it isn't, then there is no transformation. - // There is no direct method to get the parent screen so we need - // to search every screen until we find ourselves. - if (!parent && qt_screen != this) - parent = parentScreen(qt_screen, this); - if (!parent) - return 0; - if (parent->classId() != QScreen::TransformedClass) - return 0; - return 90 * static_cast<const QTransformedScreen *>(parent) - ->transformation(); -} - -#else - -int PvrEglScreen::transformation() const -{ - return 0; -} - -#endif - void PvrEglScreen::sync() { // Put code here to synchronize 2D and 3D operations if necessary. diff --git a/src/qt3support/widgets/q3dockarea.cpp b/src/qt3support/widgets/q3dockarea.cpp index bb34622..fbe235e 100644 --- a/src/qt3support/widgets/q3dockarea.cpp +++ b/src/qt3support/widgets/q3dockarea.cpp @@ -1139,7 +1139,7 @@ void Q3DockArea::setAcceptDockWindow(Q3DockWindow *dw, bool accept) { if (accept) forbiddenWidgets.removeAll(dw); - else if (forbiddenWidgets.contains(dw)) + else if (!forbiddenWidgets.contains(dw)) forbiddenWidgets.append(dw); } |