summaryrefslogtreecommitdiffstats
path: root/src/3rdparty
diff options
context:
space:
mode:
authorGareth Stockwell <gareth.stockwell@sosco.com>2009-09-22 08:39:23 (GMT)
committerFrans Englich <frans.englich@nokia.com>2009-09-23 12:39:57 (GMT)
commit1212b4c995ed9daf88183b1c0995f7115c9de97d (patch)
tree9f9dfa05eef01ab7a15ce4a51a6a1fa9f47bafba /src/3rdparty
parentd592885c48693426c7c5559920f4cd574235470e (diff)
downloadQt-1212b4c995ed9daf88183b1c0995f7115c9de97d.zip
Qt-1212b4c995ed9daf88183b1c0995f7115c9de97d.tar.gz
Qt-1212b4c995ed9daf88183b1c0995f7115c9de97d.tar.bz2
Removed hack used to silence video playback, during earlier testing
Diffstat (limited to 'src/3rdparty')
-rw-r--r--src/3rdparty/phonon/mmf/videoplayer.cpp2
1 files changed, 0 insertions, 2 deletions
diff --git a/src/3rdparty/phonon/mmf/videoplayer.cpp b/src/3rdparty/phonon/mmf/videoplayer.cpp
index 7b4626c..6c4641d 100644
--- a/src/3rdparty/phonon/mmf/videoplayer.cpp
+++ b/src/3rdparty/phonon/mmf/videoplayer.cpp
@@ -125,9 +125,7 @@ void MMF::VideoPlayer::doPlay()
updateMmfOutput();
}
- TRAP_IGNORE(m_player->SetVolumeL(0)); // *** HACK ***
m_player->Play();
- TRAP_IGNORE(m_player->SetVolumeL(0)); // *** HACK ***
}
void MMF::VideoPlayer::doPause()
alue) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Constant, value); +} + +/*! + Sets the \c FINAL flag on this property to \a value. + + \sa isFinal() +*/ +void QMetaPropertyBuilder::setFinal(bool value) +{ + QMetaPropertyBuilderPrivate *d = d_func(); + if (d) + d->setFlag(Final, value); +} + + +/*! \class QMetaEnumBuilder \internal \brief The QMetaEnumBuilder class enables modifications to an enumerator definition on a meta object builder. diff --git a/src/declarative/qml/qmetaobjectbuilder_p.h b/src/declarative/qml/qmetaobjectbuilder_p.h index 2678bff..392e13b 100644 --- a/src/declarative/qml/qmetaobjectbuilder_p.h +++ b/src/declarative/qml/qmetaobjectbuilder_p.h @@ -258,6 +258,8 @@ public: bool isUser() const; bool hasStdCppSet() const; bool isEnumOrFlag() const; + bool isConstant() const; + bool isFinal() const; void setReadable(bool value); void setWritable(bool value); @@ -269,6 +271,8 @@ public: void setUser(bool value); void setStdCppSet(bool value); void setEnumOrFlag(bool value); + void setConstant(bool value); + void setFinal(bool value); private: const QMetaObjectBuilder *_mobj; diff --git a/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp index 06baed8..ff72654 100644 --- a/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp +++ b/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp @@ -546,6 +546,8 @@ void tst_QMetaObjectBuilder::property() QVERIFY(!nullProp.isUser()); QVERIFY(!nullProp.hasStdCppSet()); QVERIFY(!nullProp.isEnumOrFlag()); + QVERIFY(!nullProp.isConstant()); + QVERIFY(!nullProp.isFinal()); QCOMPARE(nullProp.index(), 0); // Add a property and check its attributes. @@ -563,6 +565,8 @@ void tst_QMetaObjectBuilder::property() QVERIFY(!prop1.isUser()); QVERIFY(!prop1.hasStdCppSet()); QVERIFY(!prop1.isEnumOrFlag()); + QVERIFY(!prop1.isConstant()); + QVERIFY(!prop1.isFinal()); QCOMPARE(prop1.index(), 0); QCOMPARE(builder.propertyCount(), 1); @@ -581,6 +585,8 @@ void tst_QMetaObjectBuilder::property() QVERIFY(!prop2.isUser()); QVERIFY(!prop2.hasStdCppSet()); QVERIFY(!prop2.isEnumOrFlag()); + QVERIFY(!prop2.isConstant()); + QVERIFY(!prop2.isFinal()); QCOMPARE(prop2.index(), 1); QCOMPARE(builder.propertyCount(), 2); @@ -602,6 +608,8 @@ void tst_QMetaObjectBuilder::property() prop1.setUser(true); prop1.setStdCppSet(true); prop1.setEnumOrFlag(true); + prop1.setConstant(true); + prop1.setFinal(true); // Check that prop1 is changed, but prop2 is not. QCOMPARE(prop1.name(), QByteArray("foo")); @@ -616,6 +624,8 @@ void tst_QMetaObjectBuilder::property() QVERIFY(prop1.isUser()); QVERIFY(prop1.hasStdCppSet()); QVERIFY(prop1.isEnumOrFlag()); + QVERIFY(prop1.isConstant()); + QVERIFY(prop1.isFinal()); QVERIFY(prop2.isReadable()); QVERIFY(prop2.isWritable()); QCOMPARE(prop2.name(), QByteArray("bar")); @@ -628,6 +638,8 @@ void tst_QMetaObjectBuilder::property() QVERIFY(!prop2.isUser()); QVERIFY(!prop2.hasStdCppSet()); QVERIFY(!prop2.isEnumOrFlag()); + QVERIFY(!prop2.isConstant()); + QVERIFY(!prop2.isFinal()); // Remove prop1 and check that prop2 becomes index 0. builder.removeProperty(0); @@ -643,6 +655,8 @@ void tst_QMetaObjectBuilder::property() QVERIFY(!prop2.isUser()); QVERIFY(!prop2.hasStdCppSet()); QVERIFY(!prop2.isEnumOrFlag()); + QVERIFY(!prop2.isConstant()); + QVERIFY(!prop2.isFinal()); QCOMPARE(prop2.index(), 0); // Perform index-based lookup again. @@ -666,6 +680,8 @@ void tst_QMetaObjectBuilder::property() prop2.setUser(false); \ prop2.setStdCppSet(false); \ prop2.setEnumOrFlag(false); \ + prop2.setConstant(false); \ + prop2.setFinal(false); \ } while (0) #define COUNT_FLAGS() \ ((prop2.isReadable() ? 1 : 0) + \ @@ -677,7 +693,9 @@ void tst_QMetaObjectBuilder::property() (prop2.isEditable() ? 1 : 0) + \ (prop2.isUser() ? 1 : 0) + \ (prop2.hasStdCppSet() ? 1 : 0) + \ - (prop2.isEnumOrFlag() ? 1 : 0)) + (prop2.isEnumOrFlag() ? 1 : 0) + \ + (prop2.isConstant() ? 1 : 0) + \ + (prop2.isFinal() ? 1 : 0)) #define CHECK_FLAG(setFunc,isFunc) \ do { \ CLEAR_FLAGS(); \ @@ -696,6 +714,8 @@ void tst_QMetaObjectBuilder::property() CHECK_FLAG(setUser, isUser); CHECK_FLAG(setStdCppSet, hasStdCppSet); CHECK_FLAG(setEnumOrFlag, isEnumOrFlag); + CHECK_FLAG(setConstant, isConstant); + CHECK_FLAG(setFinal, isFinal); // Check that nothing else changed. QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Properties)); -- cgit v0.12 From e3cd651d92a9e550fe52360d1be6ae41d0f2ab85 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Sun, 12 Dec 2010 22:11:23 +0100 Subject: Use the virtual API to clear a selection. Reviewed-by: Gabriel de Dietrich Merge-request: 980 --- src/gui/itemviews/qitemselectionmodel.cpp | 7 +-- .../tst_qitemselectionmodel.cpp | 54 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/gui/itemviews/qitemselectionmodel.cpp b/src/gui/itemviews/qitemselectionmodel.cpp index 27a4a40..0b64452 100644 --- a/src/gui/itemviews/qitemselectionmodel.cpp +++ b/src/gui/itemviews/qitemselectionmodel.cpp @@ -1145,11 +1145,8 @@ void QItemSelectionModel::clearSelection() Q_D(QItemSelectionModel); if (d->ranges.count() == 0 && d->currentSelection.count() == 0) return; - QItemSelection selection = d->ranges; - selection.merge(d->currentSelection, d->currentCommand); - d->ranges.clear(); - d->currentSelection.clear(); - emit selectionChanged(QItemSelection(), selection); + + select(QItemSelection(), Clear); } diff --git a/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp b/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp index 6e20fb2..d91b068 100644 --- a/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp +++ b/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp @@ -101,6 +101,7 @@ private slots: void testDifferentModels(); void testValidRangesInSelectionsAfterReset(); + void testChainedSelectionClear(); private: QAbstractItemModel *model; @@ -2655,5 +2656,58 @@ void tst_QItemSelectionModel::testValidRangesInSelectionsAfterReset() model.setStringList(strings); } +class DuplicateItemSelectionModel : public QItemSelectionModel +{ + Q_OBJECT +public: + DuplicateItemSelectionModel(QItemSelectionModel *target, QAbstractItemModel *model, QObject *parent = 0) + : QItemSelectionModel(model, parent), m_target(target) + { + + } + + void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) + { + QItemSelectionModel::select(selection, command); + m_target->select(selection, command); + } + + using QItemSelectionModel::select; + +private: + QItemSelectionModel *m_target; + +}; + +void tst_QItemSelectionModel::testChainedSelectionClear() +{ + QStringListModel model(QStringList() << "Apples" << "Pears"); + + QItemSelectionModel selectionModel(&model, 0); + DuplicateItemSelectionModel duplicate(&selectionModel, &model, 0); + + duplicate.select(model.index(0, 0), QItemSelectionModel::Select); + + { + QModelIndexList selectedIndexes = selectionModel.selection().indexes(); + QModelIndexList duplicatedIndexes = duplicate.selection().indexes(); + + QVERIFY(selectedIndexes.size() == duplicatedIndexes.size()); + QVERIFY(selectedIndexes.size() == 1); + QVERIFY(selectedIndexes.first() == model.index(0, 0)); + } + + duplicate.clearSelection(); + + { + QModelIndexList selectedIndexes = selectionModel.selection().indexes(); + QModelIndexList duplicatedIndexes = duplicate.selection().indexes(); + + QVERIFY(selectedIndexes.size() == duplicatedIndexes.size()); + QVERIFY(selectedIndexes.size() == 0); + } + +} + QTEST_MAIN(tst_QItemSelectionModel) #include "tst_qitemselectionmodel.moc" -- cgit v0.12 From 99512251be8e5814238ec398854a8aa71fa8b25d Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Wed, 16 Mar 2011 10:23:06 +1000 Subject: Optimization and benchmark for setting object properties from QML. Change-Id: Ib923e5d3946e99001ef682a9dd8ca6d7788818a3 Reviewed-by: Aaron Kennedy --- .../qml/qdeclarativeobjectscriptclass.cpp | 27 ++++++++++++ .../qdeclarativeecmascript/data/realToInt.qml | 11 +++++ .../tst_qdeclarativeecmascript.cpp | 13 ++++++ tests/benchmarks/declarative/script/tst_script.cpp | 49 +++++++++++++++++++++- 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/realToInt.qml diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index dc3ecca..e7ab9cd 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -395,6 +395,33 @@ void QDeclarativeObjectScriptClass::setProperty(QObject *obj, } else if (value.isFunction() && !value.isRegExp()) { // this is handled by the binding creation above } else { + //### expand optimization for other known types + if (lastData->propType == QMetaType::Int && value.isNumber()) { + int rawValue = qRound(value.toNumber()); + int status = -1; + int flags = 0; + void *a[] = { (void *)&rawValue, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, + lastData->coreIndex, a); + return; + } else if (lastData->propType == QMetaType::QReal && value.isNumber()) { + qreal rawValue = qreal(value.toNumber()); + int status = -1; + int flags = 0; + void *a[] = { (void *)&rawValue, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, + lastData->coreIndex, a); + return; + } else if (lastData->propType == QMetaType::QString && value.isString()) { + const QString &rawValue = value.toString(); + int status = -1; + int flags = 0; + void *a[] = { (void *)&rawValue, 0, &status, &flags }; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, + lastData->coreIndex, a); + return; + } + QVariant v; if (lastData->flags & QDeclarativePropertyCache::Data::IsQList) v = enginePriv->scriptValueToVariant(value, qMetaTypeId >()); diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/realToInt.qml b/tests/auto/declarative/qdeclarativeecmascript/data/realToInt.qml new file mode 100644 index 0000000..cbbbbf9 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/realToInt.qml @@ -0,0 +1,11 @@ +import QtQuick 1.0 +import Qt.test 1.0 + +MyQmlObject { + function test1() { + value = 4.2 + } + function test2() { + value = 7.9 + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 40b0e1b..2f5581a 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -176,6 +176,7 @@ private slots: void aliasBindingsOverrideTarget(); void aliasWritesOverrideBindings(); void pushCleanContext(); + void realToInt(); void include(); @@ -3055,6 +3056,18 @@ void tst_qdeclarativeecmascript::pushCleanContext() QCOMPARE(func2.call().toInt32(), 6); } +void tst_qdeclarativeecmascript::realToInt() +{ + QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml")); + MyQmlObject *object = qobject_cast(component.create()); + QVERIFY(object != 0); + + QMetaObject::invokeMethod(object, "test1"); + QCOMPARE(object->value(), int(4)); + QMetaObject::invokeMethod(object, "test2"); + QCOMPARE(object->value(), int(8)); +} + QTEST_MAIN(tst_qdeclarativeecmascript) #include "tst_qdeclarativeecmascript.moc" diff --git a/tests/benchmarks/declarative/script/tst_script.cpp b/tests/benchmarks/declarative/script/tst_script.cpp index 2020a18..b07ffa1 100644 --- a/tests/benchmarks/declarative/script/tst_script.cpp +++ b/tests/benchmarks/declarative/script/tst_script.cpp @@ -70,6 +70,9 @@ private slots: void property_qobject(); void property_qmlobject(); + void setproperty_js(); + void setproperty_qmlobject(); + void function_js(); void function_cpp(); void function_qobject(); @@ -108,12 +111,13 @@ inline QUrl TEST_FILE(const QString &filename) class TestObject : public QObject { Q_OBJECT - Q_PROPERTY(int x READ x) + Q_PROPERTY(int x READ x WRITE setX) public: TestObject(QObject *parent = 0); int x(); + void setX(int x) { m_x = x; } void emitMySignal() { emit mySignal(); } void emitMySignalWithArgs(int n) { emit mySignalWithArgs(n); } @@ -323,6 +327,49 @@ void tst_script::property_qmlobject() } } +#define SETPROPERTY_PROGRAM \ + "(function(testObject) { return (function() { " \ + " for (var ii = 0; ii < 10000; ++ii) { " \ + " testObject.x = ii; " \ + " } " \ + "}); })" + +void tst_script::setproperty_js() +{ + QScriptEngine engine; + + QScriptValue v = engine.newObject(); + v.setProperty(QLatin1String("x"), 0); + + QScriptValueList args; + args << v; + QScriptValue prog = engine.evaluate(SETPROPERTY_PROGRAM).call(engine.globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + +void tst_script::setproperty_qmlobject() +{ + QDeclarativeEngine qmlengine; + + QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(&qmlengine); + TestObject to; + + QScriptValue v = QDeclarativeEnginePrivate::get(&qmlengine)->objectClass->newQObject(&to); + + QScriptValueList args; + args << v; + QScriptValue prog = engine->evaluate(SETPROPERTY_PROGRAM).call(engine->globalObject(), args); + prog.call(); + + QBENCHMARK { + prog.call(); + } +} + #define FUNCTION_PROGRAM \ "(function(testObject) { return (function() { " \ " var test = 0; " \ -- cgit v0.12 From b3f605aebb90dc651e73a252788a81cb530a74b9 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Fri, 18 Feb 2011 16:19:23 +1000 Subject: Stop the animation driver when there are no more animations. Change-Id: If03c9e4539e984db725f7e7d89e8b565890fcbed Reviewed-by: Gunnar Sletta --- src/corelib/animation/qabstractanimation.cpp | 3 ++- src/corelib/animation/qabstractanimation_p.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 2d5cfab..a562542 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -254,7 +254,8 @@ void QUnifiedTimer::restartAnimationTimer() } else if (!driver->isRunning() || isPauseTimerActive) { driver->start(); isPauseTimerActive = false; - } + } else if (runningLeafAnimations == 0) + driver->stop(); } void QUnifiedTimer::setTimingInterval(int interval) diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h index 1ab05cd..2c0eee7 100644 --- a/src/corelib/animation/qabstractanimation_p.h +++ b/src/corelib/animation/qabstractanimation_p.h @@ -184,6 +184,9 @@ public: void restartAnimationTimer(); void updateAnimationsTime(); + //useful for profiling/debugging + int runningAnimationCount() { return animations.count(); } + protected: void timerEvent(QTimerEvent *); -- cgit v0.12 From 6cd51aeec11e7a70ba560c350274d5a4bd43c9b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Mill=C3=A1n=20Soto?= Date: Sun, 20 Mar 2011 19:19:32 +0100 Subject: QAccessibleTextEdit: Using x coordinate for calculate character width Merge-request: 1148 Task-number: QTBUG-18233 Reviewed-by: Frederik Gladhorn --- src/plugins/accessible/widgets/qaccessiblewidgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp index 09b5015..ca3f827 100644 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp @@ -1334,7 +1334,7 @@ QRect QAccessibleTextEdit::characterRect(int offset, CoordinateType coordType) QRect r = edit->cursorRect(cursor); if (cursor.movePosition(QTextCursor::NextCharacter)) { - r.setWidth(edit->cursorRect(cursor).y() - r.y()); + r.setWidth(edit->cursorRect(cursor).x() - r.x()); } else { // we don't know the width of the character - maybe because we're at document end // in that case, IAccessible2 tells us to return the width of a default character -- cgit v0.12 From 8888cef411ce1d1fc898970429e951f9ef623b0e Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Tue, 22 Mar 2011 14:32:02 +0100 Subject: Unit test for characterRect in Accessible TextInterface. --- tests/auto/qaccessibility/tst_qaccessibility.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/auto/qaccessibility/tst_qaccessibility.cpp b/tests/auto/qaccessibility/tst_qaccessibility.cpp index 8d9603b..72254be 100644 --- a/tests/auto/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/qaccessibility/tst_qaccessibility.cpp @@ -2679,6 +2679,11 @@ void tst_QAccessibility::textEditTest() QCOMPARE(iface->text(QAccessible::Value, 4), QString("hello world")); QCOMPARE(iface->text(QAccessible::Value, 5), QString("how are you today?")); QCOMPARE(iface->text(QAccessible::Value, 6), QString()); + QCOMPARE(iface->textInterface()->characterCount(), 31); + QFontMetrics fm(edit.font()); + QCOMPARE(iface->textInterface()->characterRect(0, QAccessible2::RelativeToParent).size(), QSize(fm.width("h"), fm.height())); + QCOMPARE(iface->textInterface()->characterRect(5, QAccessible2::RelativeToParent).size(), QSize(fm.width(" "), fm.height())); + QCOMPARE(iface->textInterface()->characterRect(6, QAccessible2::RelativeToParent).size(), QSize(fm.width("w"), fm.height())); } QTestAccessibility::clearEvents(); #else -- cgit v0.12 From 0f5feed7dc260eabe1c2784a168e0b2fcc85e1d8 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 16 Mar 2011 17:20:32 +1000 Subject: Fix QUnifiedTimer bug Pause animations (like Timer) could trigger a jump to the next tick, which meant that other pause animations would have missed the interval skipped by the pause. Change-Id: Idebe4cbe70b2a1536d684288fc1c5d65e4c5df84 Cherry-pick-of: 115d437efb25adc2262460e001c034ea3cd8ba14 Task-number: QTBUG-18126 Reviewed-by: Leo Cunha Reviewed-by: Michael Brasser --- src/corelib/animation/qabstractanimation.cpp | 8 +++++++- src/corelib/animation/qabstractanimation_p.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index a562542..55e511d 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -167,7 +167,7 @@ Q_GLOBAL_STATIC(QThreadStorage, unifiedTimer) QUnifiedTimer::QUnifiedTimer() : QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL), - currentAnimationIdx(0), consistentTiming(false), slowMode(false), + insideTick(false), currentAnimationIdx(0), consistentTiming(false), slowMode(false), slowdownFactor(5.0f), isPauseTimerActive(false), runningLeafAnimations(0) { time.invalidate(); @@ -206,6 +206,10 @@ void QUnifiedTimer::ensureTimerUpdate() void QUnifiedTimer::updateAnimationsTime() { + //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations + if(insideTick) + return; + qint64 totalElapsed = time.elapsed(); // ignore consistentTiming in case the pause timer is active int delta = (consistentTiming && !isPauseTimerActive) ? @@ -223,12 +227,14 @@ void QUnifiedTimer::updateAnimationsTime() //it might happen in some cases that the time doesn't change because events are delayed //when the CPU load is high if (delta) { + insideTick = true; for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) { QAbstractAnimation *animation = animations.at(currentAnimationIdx); int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta); animation->setCurrentTime(elapsed); } + insideTick = false; currentAnimationIdx = 0; } } diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h index 2c0eee7..0ccc502 100644 --- a/src/corelib/animation/qabstractanimation_p.h +++ b/src/corelib/animation/qabstractanimation_p.h @@ -205,6 +205,7 @@ private: qint64 lastTick; int timingInterval; int currentAnimationIdx; + bool insideTick; bool consistentTiming; bool slowMode; -- cgit v0.12 From e783275cfb71e7325472b3aea54e109a7a854bf7 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Thu, 17 Feb 2011 19:56:30 +0100 Subject: Call QAccessible::updateAccessibility when changing accessible name. Reviewed-by: Jan-Arve --- src/gui/kernel/qwidget.cpp | 2 ++ tests/auto/qaccessibility/tst_qaccessibility.cpp | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index bf9f6f9..feedb2a 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -11153,6 +11153,7 @@ void QWidget::setAccessibleName(const QString &name) { Q_D(QWidget); d->accessibleName = name; + QAccessible::updateAccessibility(this, 0, QAccessible::NameChanged); } QString QWidget::accessibleName() const @@ -11174,6 +11175,7 @@ void QWidget::setAccessibleDescription(const QString &description) { Q_D(QWidget); d->accessibleDescription = description; + QAccessible::updateAccessibility(this, 0, QAccessible::DescriptionChanged); } QString QWidget::accessibleDescription() const diff --git a/tests/auto/qaccessibility/tst_qaccessibility.cpp b/tests/auto/qaccessibility/tst_qaccessibility.cpp index 72254be..f82502e 100644 --- a/tests/auto/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/qaccessibility/tst_qaccessibility.cpp @@ -479,6 +479,11 @@ void tst_QAccessibility::eventTest() QVERIFY_EVENT(button, 0, QAccessible::StateChanged); QVERIFY_EVENT(button, 0, QAccessible::StateChanged); + button->setAccessibleName("Olaf the second"); + QVERIFY_EVENT(button, 0, QAccessible::NameChanged); + button->setAccessibleDescription("This is a button labeled Olaf"); + QVERIFY_EVENT(button, 0, QAccessible::DescriptionChanged); + button->hide(); QVERIFY_EVENT(button, 0, QAccessible::ObjectHide); -- cgit v0.12 From 9a5b0d7a579572cd7e7faf869ab1a6684800f592 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Thu, 17 Feb 2011 15:37:43 +0100 Subject: Window and Application fixes for accessibility. Return app name instead of window title for root accessibility object. Return Window as accessible type for the main window. Reviewed-by: Jan-Arve --- src/gui/accessible/qaccessibleobject.cpp | 4 +-- .../accessible/widgets/qaccessiblewidgets.cpp | 2 +- tests/auto/qaccessibility/tst_qaccessibility.cpp | 37 ++++++++++++++++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/gui/accessible/qaccessibleobject.cpp b/src/gui/accessible/qaccessibleobject.cpp index 1d2d1da..0cb2c08 100644 --- a/src/gui/accessible/qaccessibleobject.cpp +++ b/src/gui/accessible/qaccessibleobject.cpp @@ -322,9 +322,7 @@ QString QAccessibleApplication::text(Text t, int) const { switch (t) { case Name: - if (QApplication::activeWindow()) - return QApplication::activeWindow()->windowTitle(); - break; + return QApplication::applicationName(); case Description: return QApplication::applicationFilePath(); default: diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp index ca3f827..c9db1dc 100644 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp @@ -1603,7 +1603,7 @@ void QAccessibleTextEdit::setAttributes(int startOffset, int endOffset, const QS #ifndef QT_NO_MAINWINDOW QAccessibleMainWindow::QAccessibleMainWindow(QWidget *widget) - : QAccessibleWidgetEx(widget, Application) { } + : QAccessibleWidgetEx(widget, Window) { } QVariant QAccessibleMainWindow::invokeMethodEx(QAccessible::Method /*method*/, int /*child*/, const QVariantList & /*params*/) { diff --git a/tests/auto/qaccessibility/tst_qaccessibility.cpp b/tests/auto/qaccessibility/tst_qaccessibility.cpp index f82502e..6a35843 100644 --- a/tests/auto/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/qaccessibility/tst_qaccessibility.cpp @@ -245,6 +245,8 @@ private slots: void actionText(); void doAction(); + void applicationTest(); + void mainWindowTest(); void buttonTest(); void sliderTest(); void scrollBarTest(); @@ -1826,6 +1828,41 @@ void tst_QAccessibility::doAction() #endif } +void tst_QAccessibility::applicationTest() +{ +#ifdef QTEST_ACCESSIBILITY + QLatin1String name = QLatin1String("My Name"); + qApp->setApplicationName(name); + QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(qApp); + QCOMPARE(interface->text(QAccessible::Name, 0), name); + QCOMPARE(interface->role(0), QAccessible::Application); + delete interface; +#else + QSKIP("Test needs accessibility support.", SkipAll); +#endif +} + +void tst_QAccessibility::mainWindowTest() +{ +#ifdef QTEST_ACCESSIBILITY + QMainWindow mw; + mw.resize(300, 200); + mw.show(); // triggers layout + + QLatin1String name = QLatin1String("I am the main window"); + mw.setWindowTitle(name); + QTest::qWaitForWindowShown(&mw); + + QAccessibleInterface *interface = QAccessible::queryAccessibleInterface(&mw); + QCOMPARE(interface->text(QAccessible::Name, 0), name); + QCOMPARE(interface->role(0), QAccessible::Window); + delete interface; + +#else + QSKIP("Test needs accessibility support.", SkipAll); +#endif +} + void tst_QAccessibility::buttonTest() { //#ifdef QTEST_ACCESSIBILITY -- cgit v0.12 From 6040eeebfb1ab3be3906295c373033cd5b5d9dc3 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Mon, 14 Mar 2011 18:57:27 +0100 Subject: Fix text for checkable buttons, unit tests. Return Check/Uncheck for checkable buttons. Partially revive the buttons unit test. Reviewed-by: Jan-Arve --- src/plugins/accessible/widgets/simplewidgets.cpp | 17 ++ tests/auto/qaccessibility/tst_qaccessibility.cpp | 290 ++++++++++++----------- 2 files changed, 175 insertions(+), 132 deletions(-) diff --git a/src/plugins/accessible/widgets/simplewidgets.cpp b/src/plugins/accessible/widgets/simplewidgets.cpp index 21d2d67..1510292 100644 --- a/src/plugins/accessible/widgets/simplewidgets.cpp +++ b/src/plugins/accessible/widgets/simplewidgets.cpp @@ -227,6 +227,9 @@ QString QAccessibleButton::description(int actionIndex) { switch (actionIndex) { case 0: + if (button()->isCheckable()) { + return QLatin1String("Toggles the button."); + } return QLatin1String("Clicks the button."); default: return QString(); @@ -237,6 +240,13 @@ QString QAccessibleButton::name(int actionIndex) { switch (actionIndex) { case 0: + if (button()->isCheckable()) { + if (button()->isChecked()) { + return QLatin1String("Uncheck"); + } else { + return QLatin1String("Check"); + } + } return QLatin1String("Press"); default: return QString(); @@ -247,6 +257,13 @@ QString QAccessibleButton::localizedName(int actionIndex) { switch (actionIndex) { case 0: + if (button()->isCheckable()) { + if (button()->isChecked()) { + return tr("Uncheck"); + } else { + return tr("Check"); + } + } return tr("Press"); default: return QString(); diff --git a/tests/auto/qaccessibility/tst_qaccessibility.cpp b/tests/auto/qaccessibility/tst_qaccessibility.cpp index 6a35843..64bd879 100644 --- a/tests/auto/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/qaccessibility/tst_qaccessibility.cpp @@ -1863,49 +1863,67 @@ void tst_QAccessibility::mainWindowTest() #endif } +class CounterButton : public QPushButton { + Q_OBJECT +public: + CounterButton(const QString& name, QWidget* parent) + : QPushButton(name, parent), clickCount(0) + { + connect(this, SIGNAL(clicked(bool)), SLOT(incClickCount())); + } + int clickCount; +public Q_SLOTS: + void incClickCount() { + ++clickCount; + } +}; + void tst_QAccessibility::buttonTest() { -//#ifdef QTEST_ACCESSIBILITY -#if 0 +#ifdef QTEST_ACCESSIBILITY QAccessibleInterface *test = 0; - Q3VBox vbox; + + QWidget window; + window.setLayout(new QVBoxLayout); // Standard push button - QPushButton pushButton("Ok", &vbox); + CounterButton pushButton("Ok", &window); // toggle push button - QPushButton togglepush("Toggle", &vbox); - togglepush.setToggleButton(TRUE); + QPushButton togglepush("Toggle", &window); + togglepush.setToggleButton(true); - // push button with a menu - QPushButton menuButton("Menu", &vbox); - Q3PopupMenu buttonMenu(&menuButton); - buttonMenu.insertItem("Some item"); - menuButton.setPopup(&buttonMenu); // standard checkbox - QCheckBox checkBox("Check me!", &vbox); + QCheckBox checkBox("Check me!", &window); // tristate checkbox - QCheckBox tristate("Tristate!", &vbox); + QCheckBox tristate("Tristate!", &window); tristate.setTristate(TRUE); // radiobutton - QRadioButton radio("Radio me!", &vbox); + QRadioButton radio("Radio me!", &window); // standard toolbutton - QToolButton toolbutton(&vbox); + QToolButton toolbutton(&window); toolbutton.setText("Tool"); toolbutton.setMinimumSize(20,20); // standard toolbutton - QToolButton toggletool(&vbox); + QToolButton toggletool(&window); toggletool.setToggleButton(TRUE); toggletool.setText("Toggle"); toggletool.setMinimumSize(20,20); +#ifdef QT3_SUPPORT + // push button with a menu + QPushButton menuButton("Menu", &window); + Q3PopupMenu buttonMenu(&menuButton); + buttonMenu.insertItem("Some item"); + menuButton.setPopup(&buttonMenu); + // menu toolbutton - QToolButton menuToolButton(&vbox); + QToolButton menuToolButton(&window); menuToolButton.setText("Menu Tool"); Q3PopupMenu toolMenu(&menuToolButton); toolMenu.insertItem("Some item"); @@ -1913,141 +1931,149 @@ void tst_QAccessibility::buttonTest() menuToolButton.setMinimumSize(20,20); // splitted menu toolbutton - QToolButton splitToolButton(&vbox); + QToolButton splitToolButton(&window); splitToolButton.setTextLabel("Split Tool"); Q3PopupMenu splitMenu(&splitToolButton); splitMenu.insertItem("Some item"); splitToolButton.setPopup(&splitMenu); splitToolButton.setPopupDelay(0); splitToolButton.setMinimumSize(20,20); +#endif // test push button - QVERIFY(QAccessible::queryAccessibleInterface(&pushButton, &test)); - QCOMPARE(test->role(0), QAccessible::PushButton); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - pushButton.setDown(TRUE); - QCOMPARE(test->state(0), (int)QAccessible::Pressed); - QVERIFY(test->doAction(QAccessible::Press, 0)); + QAccessibleInterface* interface = QAccessible::queryAccessibleInterface(&pushButton); + QAccessibleActionInterface* actionInterface = interface->actionInterface(); + QVERIFY(actionInterface != 0); + + QCOMPARE(interface->role(0), QAccessible::PushButton); + + // currently our buttons only have click as action, press and release are missing + QCOMPARE(actionInterface->actionCount(), 1); + QCOMPARE(actionInterface->name(0), QString("Click")); + QCOMPARE(pushButton.clickCount, 0); + actionInterface->doAction(0); QTest::qWait(500); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - test->release(); - - // test toggle push button - QVERIFY(QAccessible::queryAccessibleInterface(&togglepush, &test)); - QCOMPARE(test->role(0), QAccessible::CheckBox); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - QVERIFY(test->doAction(QAccessible::Press, 0)); + QCOMPARE(pushButton.clickCount, 1); + delete interface; + + // test toggle button + interface = QAccessible::queryAccessibleInterface(&togglepush); + actionInterface = interface->actionInterface(); + QCOMPARE(interface->role(0), QAccessible::CheckBox); + QCOMPARE(actionInterface->description(0), QString("Toggles the button.")); + QCOMPARE(actionInterface->name(0), QString("Check")); + QVERIFY(!togglepush.isChecked()); + QVERIFY((interface->state(0) & QAccessible::Checked) == 0); + actionInterface->doAction(0); QTest::qWait(500); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck")); - QCOMPARE(test->state(0), (int)QAccessible::Checked); - test->release(); - - // test menu push button - QVERIFY(QAccessible::queryAccessibleInterface(&menuButton, &test)); - QCOMPARE(test->role(0), QAccessible::ButtonMenu); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Open")); - QCOMPARE(test->state(0), (int)QAccessible::HasPopup); - test->release(); + QCOMPARE(actionInterface->name(0), QString("Uncheck")); + QVERIFY(togglepush.isChecked()); + QVERIFY((interface->state(0) & QAccessible::Checked)); + delete interface; + +// // test menu push button +// QVERIFY(QAccessible::queryAccessibleInterface(&menuButton, &test)); +// QCOMPARE(test->role(0), QAccessible::ButtonMenu); +// QCOMPARE(test->defaultAction(0), QAccessible::Press); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Open")); +// QCOMPARE(test->state(0), (int)QAccessible::HasPopup); +// test->release(); // test check box - QVERIFY(QAccessible::queryAccessibleInterface(&checkBox, &test)); - QCOMPARE(test->role(0), QAccessible::CheckBox); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - QVERIFY(test->doAction(QAccessible::Press, 0)); - QTest::qWait(500); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck")); - QCOMPARE(test->state(0), (int)QAccessible::Checked); - test->release(); - - // test tristate check box - QVERIFY(QAccessible::queryAccessibleInterface(&tristate, &test)); - QCOMPARE(test->role(0), QAccessible::CheckBox); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Toggle")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - QVERIFY(test->doAction(QAccessible::Press, 0)); + interface = QAccessible::queryAccessibleInterface(&checkBox); + actionInterface = interface->actionInterface(); + QCOMPARE(interface->role(0), QAccessible::CheckBox); + QCOMPARE(actionInterface->name(0), QString("Check")); + QVERIFY((interface->state(0) & QAccessible::Checked) == 0); + actionInterface->doAction(0); QTest::qWait(500); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); - QCOMPARE(test->state(0), (int)QAccessible::Mixed); - QVERIFY(test->doAction(QAccessible::Press, 0)); - QTest::qWait(500); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck")); - QCOMPARE(test->state(0), (int)QAccessible::Checked); - test->release(); + QCOMPARE(actionInterface->name(0), QString("Uncheck")); + QVERIFY(interface->state(0) & QAccessible::Checked); + QVERIFY(checkBox.isChecked()); + delete interface; + +// // test tristate check box +// QVERIFY(QAccessible::queryAccessibleInterface(&tristate, &test)); +// QCOMPARE(test->role(0), QAccessible::CheckBox); +// QCOMPARE(test->defaultAction(0), QAccessible::Press); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Toggle")); +// QCOMPARE(test->state(0), (int)QAccessible::Normal); +// QVERIFY(test->doAction(QAccessible::Press, 0)); +// QTest::qWait(500); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); +// QCOMPARE(test->state(0), (int)QAccessible::Mixed); +// QVERIFY(test->doAction(QAccessible::Press, 0)); +// QTest::qWait(500); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck")); +// QCOMPARE(test->state(0), (int)QAccessible::Checked); +// test->release(); // test radiobutton - QVERIFY(QAccessible::queryAccessibleInterface(&radio, &test)); - QCOMPARE(test->role(0), QAccessible::RadioButton); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - QVERIFY(test->doAction(QAccessible::Press, 0)); + interface = QAccessible::queryAccessibleInterface(&radio); + actionInterface = interface->actionInterface(); + QCOMPARE(interface->role(0), QAccessible::RadioButton); + QCOMPARE(actionInterface->name(0), QString("Check")); + QVERIFY((interface->state(0) & QAccessible::Checked) == 0); + actionInterface->doAction(0); QTest::qWait(500); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); - QCOMPARE(test->state(0), (int)QAccessible::Checked); - test->release(); - - // test standard toolbutton - QVERIFY(QAccessible::queryAccessibleInterface(&toolbutton, &test)); - QCOMPARE(test->role(0), QAccessible::PushButton); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - test->release(); - - // toggle tool button - QVERIFY(QAccessible::queryAccessibleInterface(&toggletool, &test)); - QCOMPARE(test->role(0), QAccessible::CheckBox); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); - QCOMPARE(test->state(0), (int)QAccessible::Normal); - QVERIFY(test->doAction(QAccessible::Press, 0)); - QTest::qWait(500); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck")); - QCOMPARE(test->state(0), (int)QAccessible::Checked); - test->release(); - - // test menu toolbutton - QVERIFY(QAccessible::queryAccessibleInterface(&menuToolButton, &test)); - QCOMPARE(test->role(0), QAccessible::ButtonMenu); - QCOMPARE(test->defaultAction(0), 1); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Open")); - QCOMPARE(test->state(0), (int)QAccessible::HasPopup); - QCOMPARE(test->actionCount(0), 1); - QCOMPARE(test->actionText(QAccessible::Press, QAccessible::Name, 0), QString("Press")); - test->release(); - - // test splitted menu toolbutton - QVERIFY(QAccessible::queryAccessibleInterface(&splitToolButton, &test)); - QCOMPARE(test->childCount(), 2); - QCOMPARE(test->role(0), QAccessible::ButtonDropDown); - QCOMPARE(test->role(1), QAccessible::PushButton); - QCOMPARE(test->role(2), QAccessible::ButtonMenu); - QCOMPARE(test->defaultAction(0), QAccessible::Press); - QCOMPARE(test->defaultAction(1), QAccessible::Press); - QCOMPARE(test->defaultAction(2), QAccessible::Press); - QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press")); - QCOMPARE(test->state(0), (int)QAccessible::HasPopup); - QCOMPARE(test->actionCount(0), 1); - QCOMPARE(test->actionText(1, QAccessible::Name, 0), QString("Open")); - QCOMPARE(test->actionText(test->defaultAction(1), QAccessible::Name, 1), QString("Press")); - QCOMPARE(test->state(1), (int)QAccessible::Normal); - QCOMPARE(test->actionText(test->defaultAction(2), QAccessible::Name, 2), QString("Open")); - QCOMPARE(test->state(2), (int)QAccessible::HasPopup); - test->release(); + QCOMPARE(actionInterface->name(0), QString("Uncheck")); + QVERIFY(interface->state(0) & QAccessible::Checked); + QVERIFY(checkBox.isChecked()); + delete interface; + +// // test standard toolbutton +// QVERIFY(QAccessible::queryAccessibleInterface(&toolbutton, &test)); +// QCOMPARE(test->role(0), QAccessible::PushButton); +// QCOMPARE(test->defaultAction(0), QAccessible::Press); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press")); +// QCOMPARE(test->state(0), (int)QAccessible::Normal); +// test->release(); + +// // toggle tool button +// QVERIFY(QAccessible::queryAccessibleInterface(&toggletool, &test)); +// QCOMPARE(test->role(0), QAccessible::CheckBox); +// QCOMPARE(test->defaultAction(0), QAccessible::Press); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Check")); +// QCOMPARE(test->state(0), (int)QAccessible::Normal); +// QVERIFY(test->doAction(QAccessible::Press, 0)); +// QTest::qWait(500); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Uncheck")); +// QCOMPARE(test->state(0), (int)QAccessible::Checked); +// test->release(); + +// // test menu toolbutton +// QVERIFY(QAccessible::queryAccessibleInterface(&menuToolButton, &test)); +// QCOMPARE(test->role(0), QAccessible::ButtonMenu); +// QCOMPARE(test->defaultAction(0), 1); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Open")); +// QCOMPARE(test->state(0), (int)QAccessible::HasPopup); +// QCOMPARE(test->actionCount(0), 1); +// QCOMPARE(test->actionText(QAccessible::Press, QAccessible::Name, 0), QString("Press")); +// test->release(); + +// // test splitted menu toolbutton +// QVERIFY(QAccessible::queryAccessibleInterface(&splitToolButton, &test)); +// QCOMPARE(test->childCount(), 2); +// QCOMPARE(test->role(0), QAccessible::ButtonDropDown); +// QCOMPARE(test->role(1), QAccessible::PushButton); +// QCOMPARE(test->role(2), QAccessible::ButtonMenu); +// QCOMPARE(test->defaultAction(0), QAccessible::Press); +// QCOMPARE(test->defaultAction(1), QAccessible::Press); +// QCOMPARE(test->defaultAction(2), QAccessible::Press); +// QCOMPARE(test->actionText(test->defaultAction(0), QAccessible::Name, 0), QString("Press")); +// QCOMPARE(test->state(0), (int)QAccessible::HasPopup); +// QCOMPARE(test->actionCount(0), 1); +// QCOMPARE(test->actionText(1, QAccessible::Name, 0), QString("Open")); +// QCOMPARE(test->actionText(test->defaultAction(1), QAccessible::Name, 1), QString("Press")); +// QCOMPARE(test->state(1), (int)QAccessible::Normal); +// QCOMPARE(test->actionText(test->defaultAction(2), QAccessible::Name, 2), QString("Open")); +// QCOMPARE(test->state(2), (int)QAccessible::HasPopup); +// test->release(); QTestAccessibility::clearEvents(); #else -// QSKIP("Test needs accessibility support.", SkipAll); - QSKIP("No action interface in Qt 4 yet.", SkipAll); + QSKIP("Test needs accessibility support.", SkipAll); #endif } -- cgit v0.12 From fdeeaa9d61efea9cca783a1d4098ae505df24390 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Fri, 18 Mar 2011 17:41:01 +0100 Subject: Make navigation in TabWidgets consistent. navigate would not return the right index in the parent if the current widget was not the visible one. Reviewed-by: Jan-Arve --- .../accessible/widgets/qaccessiblewidgets.cpp | 13 ++- tests/auto/qaccessibility/tst_qaccessibility.cpp | 93 +++++++++++++++++++++- 2 files changed, 99 insertions(+), 7 deletions(-) diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp index c9db1dc..4402932 100644 --- a/src/plugins/accessible/widgets/qaccessiblewidgets.cpp +++ b/src/plugins/accessible/widgets/qaccessiblewidgets.cpp @@ -401,9 +401,14 @@ int QAccessibleStackedWidget::childCount() const int QAccessibleStackedWidget::indexOfChild(const QAccessibleInterface *child) const { - if (!child || (stackedWidget()->currentWidget() != child->object())) + if (!child) return -1; - return 1; + + QWidget* widget = qobject_cast(child->object()); + int index = stackedWidget()->indexOf(widget); + if (index >= 0) // one based counting of children + return index + 1; + return -1; } int QAccessibleStackedWidget::navigate(RelationFlag relation, int entry, QAccessibleInterface **target) const @@ -413,9 +418,9 @@ int QAccessibleStackedWidget::navigate(RelationFlag relation, int entry, QAccess QObject *targetObject = 0; switch (relation) { case Child: - if (entry != 1) + if (entry < 1 || entry > stackedWidget()->count()) return -1; - targetObject = stackedWidget()->currentWidget(); + targetObject = stackedWidget()->widget(entry-1); break; default: return QAccessibleWidgetEx::navigate(relation, entry, target); diff --git a/tests/auto/qaccessibility/tst_qaccessibility.cpp b/tests/auto/qaccessibility/tst_qaccessibility.cpp index 64bd879..b8301be 100644 --- a/tests/auto/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/qaccessibility/tst_qaccessibility.cpp @@ -251,6 +251,7 @@ private slots: void sliderTest(); void scrollBarTest(); void tabTest(); + void tabWidgetTest(); void menuTest(); void spinBoxTest(); void doubleSpinBoxTest(); @@ -1881,8 +1882,6 @@ public Q_SLOTS: void tst_QAccessibility::buttonTest() { #ifdef QTEST_ACCESSIBILITY - QAccessibleInterface *test = 0; - QWidget window; window.setLayout(new QVBoxLayout); @@ -1915,7 +1914,8 @@ void tst_QAccessibility::buttonTest() toggletool.setText("Toggle"); toggletool.setMinimumSize(20,20); -#ifdef QT3_SUPPORT +#if 0 + // QT3_SUPPORT // push button with a menu QPushButton menuButton("Menu", &window); Q3PopupMenu buttonMenu(&menuButton); @@ -2418,6 +2418,93 @@ void tst_QAccessibility::tabTest() #endif } +void tst_QAccessibility::tabWidgetTest() +{ +#ifdef QTEST_ACCESSIBILITY + QTabWidget *tabWidget = new QTabWidget(); + tabWidget->show(); + + // the interface for the tab is just a container for tabbar and stacked widget + QAccessibleInterface * const interface = QAccessible::queryAccessibleInterface(tabWidget); + QVERIFY(interface); + QCOMPARE(interface->childCount(), 2); + QCOMPARE(interface->role(0), QAccessible::Client); + + // Create pages, check navigation + QLabel *label1 = new QLabel("Page 1", tabWidget); + tabWidget->addTab(label1, "Tab 1"); + QLabel *label2 = new QLabel("Page 2", tabWidget); + tabWidget->addTab(label2, "Tab 2"); + + QCOMPARE(interface->childCount(), 2); + + QAccessibleInterface* tabBarInterface = 0; + // there is no special logic to sort the children, so the contents will be 1, the tab bar 2 + QCOMPARE(interface->navigate(QAccessible::Child, 2 , &tabBarInterface), 0); + QVERIFY(tabBarInterface); + QCOMPARE(tabBarInterface->childCount(), 4); + QCOMPARE(tabBarInterface->role(0), QAccessible::PageTabList); + + QAccessibleInterface* tabButton1Interface = 0; + QCOMPARE(tabBarInterface->navigate(QAccessible::Child, 1 , &tabButton1Interface), 1); + QVERIFY(tabButton1Interface == 0); + + QCOMPARE(tabBarInterface->role(1), QAccessible::PageTab); + QCOMPARE(tabBarInterface->text(QAccessible::Name, 1), QLatin1String("Tab 1")); + QCOMPARE(tabBarInterface->role(2), QAccessible::PageTab); + QCOMPARE(tabBarInterface->text(QAccessible::Name, 2), QLatin1String("Tab 2")); + QCOMPARE(tabBarInterface->role(3), QAccessible::PushButton); + QCOMPARE(tabBarInterface->text(QAccessible::Name, 3), QLatin1String("Scroll Left")); + QCOMPARE(tabBarInterface->role(4), QAccessible::PushButton); + QCOMPARE(tabBarInterface->text(QAccessible::Name, 4), QLatin1String("Scroll Right")); + + QAccessibleInterface* stackWidgetInterface = 0; + QCOMPARE(interface->navigate(QAccessible::Child, 1, &stackWidgetInterface), 0); + QVERIFY(stackWidgetInterface); + QCOMPARE(stackWidgetInterface->childCount(), 2); + QCOMPARE(stackWidgetInterface->role(0), QAccessible::LayeredPane); + + QAccessibleInterface* stackChild1Interface = 0; + QCOMPARE(stackWidgetInterface->navigate(QAccessible::Child, 1, &stackChild1Interface), 0); + QVERIFY(stackChild1Interface); + QCOMPARE(stackChild1Interface->childCount(), 0); + QCOMPARE(stackChild1Interface->role(0), QAccessible::StaticText); + QCOMPARE(stackChild1Interface->text(QAccessible::Name, 0), QLatin1String("Page 1")); + QCOMPARE(label1, stackChild1Interface->object()); + + // Navigation in stack widgets should be consistent + QAccessibleInterface* parent = 0; + QCOMPARE(stackChild1Interface->navigate(QAccessible::Ancestor, 1, &parent), 0); + QVERIFY(parent); + QCOMPARE(parent->childCount(), 2); + QCOMPARE(parent->role(0), QAccessible::LayeredPane); + delete parent; + + QAccessibleInterface* stackChild2Interface = 0; + QCOMPARE(stackWidgetInterface->navigate(QAccessible::Child, 2, &stackChild2Interface), 0); + QVERIFY(stackChild2Interface); + QCOMPARE(stackChild2Interface->childCount(), 0); + QCOMPARE(stackChild2Interface->role(0), QAccessible::StaticText); + QCOMPARE(label2, stackChild2Interface->object()); // the text will be empty since it is not visible + + QCOMPARE(stackChild2Interface->navigate(QAccessible::Ancestor, 1, &parent), 0); + QVERIFY(parent); + QCOMPARE(parent->childCount(), 2); + QCOMPARE(parent->role(0), QAccessible::LayeredPane); + delete parent; + + delete tabBarInterface; + delete stackChild1Interface; + delete stackChild2Interface; + delete stackWidgetInterface; + delete interface; + delete tabWidget; + QTestAccessibility::clearEvents(); +#else + QSKIP("Test needs accessibility support.", SkipAll); +#endif +} + void tst_QAccessibility::menuTest() { #ifdef QTEST_ACCESSIBILITY -- cgit v0.12 From 6567653a003191508ee5561dcd9896cb97cf3ec3 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Thu, 24 Mar 2011 10:05:07 +1000 Subject: Remove compile warning Change-Id: If209db684878ab734b3265b479c59dfc27b18be1 --- src/corelib/animation/qabstractanimation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 55e511d..0a1f5d7 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -167,7 +167,7 @@ Q_GLOBAL_STATIC(QThreadStorage, unifiedTimer) QUnifiedTimer::QUnifiedTimer() : QObject(), defaultDriver(this), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL), - insideTick(false), currentAnimationIdx(0), consistentTiming(false), slowMode(false), + currentAnimationIdx(0), insideTick(false), consistentTiming(false), slowMode(false), slowdownFactor(5.0f), isPauseTimerActive(false), runningLeafAnimations(0) { time.invalidate(); -- cgit v0.12 From cdb5729d8e1ffc4a00b52d6d4bbee34a9820a193 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Thu, 24 Mar 2011 10:41:36 +0100 Subject: Cocoa: respect QT_NO_EXCEPTION in color dialog If the macro is set, we should not use cocoa exceptions either, as this causes compile failures Rev-By: jbache --- src/gui/dialogs/qcolordialog_mac.mm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/dialogs/qcolordialog_mac.mm b/src/gui/dialogs/qcolordialog_mac.mm index ee9b19a..9daf595 100644 --- a/src/gui/dialogs/qcolordialog_mac.mm +++ b/src/gui/dialogs/qcolordialog_mac.mm @@ -343,6 +343,7 @@ QT_USE_NAMESPACE mDialogIsExecuting = true; bool modalEnded = false; while (!modalEnded) { +#ifndef QT_NO_EXCEPTIONS @try { [NSApp runModalForWindow:mColorPanel]; modalEnded = true; @@ -351,6 +352,10 @@ QT_USE_NAMESPACE // clicking on 'SelectedMenuItemColor' from the 'Developer' // palette (tab three). } +#else + [NSApp runModalForWindow:mColorPanel]; + modalEnded = true; +#endif } QAbstractEventDispatcher::instance()->interrupt(); -- cgit v0.12 From 77cbbe9e47c62047ff88973d8158c42dc30fbd00 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Fri, 25 Mar 2011 10:41:32 +0100 Subject: Fix autotest. I changed a string by accident. --- tests/auto/qaccessibility/tst_qaccessibility.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qaccessibility/tst_qaccessibility.cpp b/tests/auto/qaccessibility/tst_qaccessibility.cpp index b8301be..7de0512 100644 --- a/tests/auto/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/qaccessibility/tst_qaccessibility.cpp @@ -1949,7 +1949,7 @@ void tst_QAccessibility::buttonTest() // currently our buttons only have click as action, press and release are missing QCOMPARE(actionInterface->actionCount(), 1); - QCOMPARE(actionInterface->name(0), QString("Click")); + QCOMPARE(actionInterface->name(0), QString("Press")); QCOMPARE(pushButton.clickCount, 0); actionInterface->doAction(0); QTest::qWait(500); -- cgit v0.12 From 6c9d808c5726893e9aa673ca8b0cbebae67f641c Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig Date: Mon, 28 Mar 2011 18:52:50 +0200 Subject: Don't use inactive borders for spinbox on Mac This was probably caused by the fact that the only spinbox visible in the main control panel has an inactive frame border. In XCode 4, however the spin buttons are generally attached to an active lineedit frame, so we change the default for 4.8. Reviewed-by: gabriel --- src/gui/styles/qmacstyle_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/styles/qmacstyle_mac.mm b/src/gui/styles/qmacstyle_mac.mm index 2d21628..18003ce 100644 --- a/src/gui/styles/qmacstyle_mac.mm +++ b/src/gui/styles/qmacstyle_mac.mm @@ -4707,7 +4707,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex HIThemeFrameDrawInfo fdi; fdi.version = qt_mac_hitheme_version; - fdi.state = kThemeStateInactive; + fdi.state = tds; fdi.kind = kHIThemeFrameTextFieldSquare; fdi.isFocused = false; HIRect hirect = qt_hirectForQRect(lineeditRect); -- cgit v0.12 From 504941bc50234c225f162192491815bc4d6c38cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Mon, 28 Mar 2011 09:58:28 +0200 Subject: Fixed regression where AT client did not always announce stuff properly. This fixes a regression that was created by 75e478abdf336bbdc1b00e2ca4f5293d5455a0cb. That broke accessibility on 64 bit windows, since lParam can both be 0x00000000fffffffc and 0xfffffffffffffffc. However, MSDN explicitly says that lParam should be casted to a DWORD, which would result in (an unsigned) 0xfffffffc in both cases. This can then be compared to OBJID_CLIENT (defined to ((LONG)0xFFFFFFFC). Reviewed-by: Prasanth Ullattil --- src/gui/kernel/qapplication_win.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 5f5da59..349323e 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -2361,8 +2361,13 @@ extern "C" LRESULT QT_WIN_CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wPa #ifndef QT_NO_ACCESSIBILITY case WM_GETOBJECT: { + /* On Win64, lParam can be 0x00000000fffffffc or 0xfffffffffffffffc (!), + but MSDN says that lParam should be converted to a DWORD + before its compared against OBJID_CLIENT + */ + const DWORD dwObjId = (DWORD)lParam; // Ignoring all requests while starting up - if (QApplication::startingUp() || QApplication::closingDown() || lParam != (LPARAM)OBJID_CLIENT) { + if (QApplication::startingUp() || QApplication::closingDown() || dwObjId != OBJID_CLIENT) { result = false; break; } -- cgit v0.12 From 30d7d4d990f9734ed8cdf418ee5c8361a1633b42 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 23 Mar 2011 14:51:17 +0100 Subject: QDeclarativeDebug: Handle case where client with ongoing queries is deleted Change-Id: I4be7080af1e7e8a834b927b6c6fc211db8bd90c0 Reviewed-by: Aaron Kennedy --- src/declarative/debugger/qdeclarativedebug.cpp | 46 ++++++++++++++++++++++ .../qdeclarativedebug/tst_qdeclarativedebug.cpp | 28 ++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/declarative/debugger/qdeclarativedebug.cpp b/src/declarative/debugger/qdeclarativedebug.cpp index 62eb8fe..049e05e 100644 --- a/src/declarative/debugger/qdeclarativedebug.cpp +++ b/src/declarative/debugger/qdeclarativedebug.cpp @@ -84,6 +84,7 @@ public: static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugRootContextQuery *); static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugObjectQuery *); static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugExpressionQuery *); + static void remove(QDeclarativeEngineDebug *, QDeclarativeDebugWatch *); QHash enginesQuery; QHash rootContextQuery; @@ -120,6 +121,41 @@ QDeclarativeEngineDebugPrivate::~QDeclarativeEngineDebugPrivate() { if (client) client->priv = 0; + delete client; + + QHash::iterator enginesIter = enginesQuery.begin(); + for (; enginesIter != enginesQuery.end(); ++enginesIter) { + enginesIter.value()->m_client = 0; + if (enginesIter.value()->state() == QDeclarativeDebugQuery::Waiting) + enginesIter.value()->setState(QDeclarativeDebugQuery::Error); + } + + QHash::iterator rootContextIter = rootContextQuery.begin(); + for (; rootContextIter != rootContextQuery.end(); ++rootContextIter) { + rootContextIter.value()->m_client = 0; + if (rootContextIter.value()->state() == QDeclarativeDebugQuery::Waiting) + rootContextIter.value()->setState(QDeclarativeDebugQuery::Error); + } + + QHash::iterator objectIter = objectQuery.begin(); + for (; objectIter != objectQuery.end(); ++objectIter) { + objectIter.value()->m_client = 0; + if (objectIter.value()->state() == QDeclarativeDebugQuery::Waiting) + objectIter.value()->setState(QDeclarativeDebugQuery::Error); + } + + QHash::iterator exprIter = expressionQuery.begin(); + for (; exprIter != expressionQuery.end(); ++exprIter) { + exprIter.value()->m_client = 0; + if (exprIter.value()->state() == QDeclarativeDebugQuery::Waiting) + exprIter.value()->setState(QDeclarativeDebugQuery::Error); + } + + QHash::iterator watchIter = watched.begin(); + for (; watchIter != watched.end(); ++watchIter) { + watchIter.value()->m_client = 0; + watchIter.value()->setState(QDeclarativeDebugWatch::Dead); + } } int QDeclarativeEngineDebugPrivate::getId() @@ -160,6 +196,14 @@ void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclara } } +void QDeclarativeEngineDebugPrivate::remove(QDeclarativeEngineDebug *c, QDeclarativeDebugWatch *w) +{ + if (c && w) { + QDeclarativeEngineDebugPrivate *p = (QDeclarativeEngineDebugPrivate *)QObjectPrivate::get(c); + p->watched.remove(w->m_queryId); + } +} + void QDeclarativeEngineDebugPrivate::decode(QDataStream &ds, QDeclarativeDebugObjectReference &o, bool simple) { @@ -647,6 +691,8 @@ QDeclarativeDebugWatch::QDeclarativeDebugWatch(QObject *parent) QDeclarativeDebugWatch::~QDeclarativeDebugWatch() { + if (m_client && m_queryId != -1) + QDeclarativeEngineDebugPrivate::remove(m_client, this); } int QDeclarativeDebugWatch::queryId() const diff --git a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp index 6bcb4eb..4597ab4 100644 --- a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp +++ b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp @@ -649,7 +649,13 @@ void tst_QDeclarativeDebug::queryAvailableEngines() QCOMPARE(e.name(), m_engine->objectName()); } + // Make query invalid by deleting client + q_engines = m_dbg->queryAvailableEngines(this); + QCOMPARE(q_engines->state(), QDeclarativeDebugQuery::Waiting); + delete m_dbg; + QCOMPARE(q_engines->state(), QDeclarativeDebugQuery::Error); delete q_engines; + m_dbg = new QDeclarativeEngineDebug(m_conn, this); } void tst_QDeclarativeDebug::queryRootContexts() @@ -657,6 +663,7 @@ void tst_QDeclarativeDebug::queryRootContexts() QDeclarativeDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this); waitForQuery(q_engines); int engineId = q_engines->engines()[0].debugId(); + delete q_engines; QDeclarativeDebugRootContextQuery *q_context; @@ -688,8 +695,13 @@ void tst_QDeclarativeDebug::queryRootContexts() QVERIFY(context.contexts()[0].debugId() >= 0); QCOMPARE(context.contexts()[0].name(), QString("tst_QDeclarativeDebug_childContext")); - delete q_engines; + // Make query invalid by deleting client + q_context = m_dbg->queryRootContexts(engineId, this); + QCOMPARE(q_context->state(), QDeclarativeDebugQuery::Waiting); + delete m_dbg; + QCOMPARE(q_context->state(), QDeclarativeDebugQuery::Error); delete q_context; + m_dbg = new QDeclarativeEngineDebug(m_conn, this); } void tst_QDeclarativeDebug::queryObject() @@ -721,7 +733,14 @@ void tst_QDeclarativeDebug::queryObject() delete q_engines; delete q_context; + + // Make query invalid by deleting client + q_obj = recursive ? m_dbg->queryObjectRecursive(rootObject, this) : m_dbg->queryObject(rootObject, this); + QCOMPARE(q_obj->state(), QDeclarativeDebugQuery::Waiting); + delete m_dbg; + QCOMPARE(q_obj->state(), QDeclarativeDebugQuery::Error); delete q_obj; + m_dbg = new QDeclarativeEngineDebug(m_conn, this); // check source as defined in main() QDeclarativeDebugFileReference source = obj.source(); @@ -796,7 +815,14 @@ void tst_QDeclarativeDebug::queryExpressionResult() delete q_engines; delete q_context; + + // Make query invalid by deleting client + q_expr = m_dbg->queryExpressionResult(objectId, expr, this); + QCOMPARE(q_expr->state(), QDeclarativeDebugQuery::Waiting); + delete m_dbg; + QCOMPARE(q_expr->state(), QDeclarativeDebugQuery::Error); delete q_expr; + m_dbg = new QDeclarativeEngineDebug(m_conn, this); } void tst_QDeclarativeDebug::queryExpressionResult_data() -- cgit v0.12 From e442459e15100c2fcff0f101d8004213c2ce6960 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 30 Mar 2011 13:42:06 +0200 Subject: QDeclarativeDebug: Fix test case --- tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp index 4597ab4..d3c7032 100644 --- a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp +++ b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp @@ -1012,7 +1012,7 @@ void tst_QDeclarativeDebug::setBindingForObject() // set handler // rootObject = findRootObject(); - QCOMPARE(rootObject.children().size(), 3); + QCOMPARE(rootObject.children().size(), 4); // Rectangle, Text, MouseArea, QDeclarativeComponentAttached QDeclarativeDebugObjectReference mouseAreaObject = rootObject.children().at(2); QDeclarativeDebugObjectQuery *q_obj = m_dbg->queryObjectRecursive(mouseAreaObject, this); waitForQuery(q_obj); -- cgit v0.12 From 1897ca20a343121422b354a7910814ddd37abd17 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Fri, 1 Apr 2011 12:10:13 +0200 Subject: Let QAccessibleButton::text return something even when not visible. Buttons would not report their text when hidden, which is inconsistent. Reviewed-by: Jan-Arve --- src/plugins/accessible/widgets/simplewidgets.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/accessible/widgets/simplewidgets.cpp b/src/plugins/accessible/widgets/simplewidgets.cpp index 1510292..afd2c80 100644 --- a/src/plugins/accessible/widgets/simplewidgets.cpp +++ b/src/plugins/accessible/widgets/simplewidgets.cpp @@ -155,9 +155,6 @@ bool QAccessibleButton::doAction(int action, int child, const QVariantList ¶ QString QAccessibleButton::text(Text t, int child) const { QString str; - if (!widget()->isVisible()) - return str; - switch (t) { case Accelerator: { -- cgit v0.12 From 90b4cf4b1aa0f70a62118e200e76dc1dc57985cc Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Fri, 1 Apr 2011 12:12:32 +0200 Subject: Don't crash when requesting text. Sometimes during initialization the QAccessibleItemRow will still be in an invalid state. Reviewed-by: Jan-Arve --- src/plugins/accessible/widgets/complexwidgets.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/accessible/widgets/complexwidgets.cpp b/src/plugins/accessible/widgets/complexwidgets.cpp index e638413..85be0b0 100644 --- a/src/plugins/accessible/widgets/complexwidgets.cpp +++ b/src/plugins/accessible/widgets/complexwidgets.cpp @@ -971,7 +971,11 @@ QString QAccessibleItemView::text(Text t, int child) const return QAccessibleAbstractScrollArea::text(t, child); QAccessibleItemRow item(itemView(), childIndex(child)); - return item.text(t, 1); + if (item.isValid()) { + return item.text(t, 1); + } else { + return QString(); + } } else { return QAccessibleAbstractScrollArea::text(t, child); } -- cgit v0.12 From b240f8a2ee3b7ff82a389fbf5dfd076792f385e8 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Mon, 4 Apr 2011 10:47:28 +0200 Subject: Doc: update platform notes on Mac to reflect WA_MacNoCocoaChildWindow --- doc/src/platforms/platform-notes.qdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/platforms/platform-notes.qdoc b/doc/src/platforms/platform-notes.qdoc index 113ad86..88e5ae9 100644 --- a/doc/src/platforms/platform-notes.qdoc +++ b/doc/src/platforms/platform-notes.qdoc @@ -612,7 +612,7 @@ Qt::WA_MacNormalSize, Qt::WA_MacSmallSize, Qt::WA_MacMiniSize, Qt::WA_MacVariableSize, Qt::WA_MacBrushedMetal, Qt::WA_MacAlwaysShowToolWindow, Qt::WA_MacFrameworkScaled, Qt::WA_MacNoShadow, Qt::Sheet, Qt::Drawer, Qt::MacWindowToolBarButtonHint, - QMainWindow::unifiedTitleAndToolBarOnMac + QMainWindow::unifiedTitleAndToolBarOnMac, WA_MacNoCocoaChildWindow \section2 Mixing Qt with native code Two classes are awailable for either adding native Cocoa views/controls @@ -630,7 +630,7 @@ we need to do special bookkeeping in Qt to handle this correctly, which unfortunately make mixing in native panels hard. The best way at the moment to do this, is to follow the pattern below, where we post the call to the - function with native code rather than calling it directly. Then we now that + function with native code rather than calling it directly. Then we know that Qt has cleanly updated any pending event loop recursions before the native panel is shown: -- cgit v0.12 From d8941c0c0e3e3019a2048ae470e4e46111a2cfcf Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Mon, 4 Apr 2011 11:50:31 +0200 Subject: Remove Qt3ism: setToggleButton - setCheckable Reviewed-by: Jan-Arve --- tests/auto/qaccessibility/tst_qaccessibility.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/auto/qaccessibility/tst_qaccessibility.cpp b/tests/auto/qaccessibility/tst_qaccessibility.cpp index 7de0512..b13f6dd 100644 --- a/tests/auto/qaccessibility/tst_qaccessibility.cpp +++ b/tests/auto/qaccessibility/tst_qaccessibility.cpp @@ -1888,10 +1888,9 @@ void tst_QAccessibility::buttonTest() // Standard push button CounterButton pushButton("Ok", &window); - // toggle push button - QPushButton togglepush("Toggle", &window); - togglepush.setToggleButton(true); - + // toggle button + QPushButton toggleButton("Toggle", &window); + toggleButton.setCheckable(true); // standard checkbox QCheckBox checkBox("Check me!", &window); @@ -1910,7 +1909,7 @@ void tst_QAccessibility::buttonTest() // standard toolbutton QToolButton toggletool(&window); - toggletool.setToggleButton(TRUE); + toggletool.setCheckable(true); toggletool.setText("Toggle"); toggletool.setMinimumSize(20,20); @@ -1957,17 +1956,17 @@ void tst_QAccessibility::buttonTest() delete interface; // test toggle button - interface = QAccessible::queryAccessibleInterface(&togglepush); + interface = QAccessible::queryAccessibleInterface(&toggleButton); actionInterface = interface->actionInterface(); QCOMPARE(interface->role(0), QAccessible::CheckBox); QCOMPARE(actionInterface->description(0), QString("Toggles the button.")); QCOMPARE(actionInterface->name(0), QString("Check")); - QVERIFY(!togglepush.isChecked()); + QVERIFY(!toggleButton.isChecked()); QVERIFY((interface->state(0) & QAccessible::Checked) == 0); actionInterface->doAction(0); QTest::qWait(500); QCOMPARE(actionInterface->name(0), QString("Uncheck")); - QVERIFY(togglepush.isChecked()); + QVERIFY(toggleButton.isChecked()); QVERIFY((interface->state(0) & QAccessible::Checked)); delete interface; -- cgit v0.12 From b60d82fd56897b1a1d3cc730172f71c27a497ede Mon Sep 17 00:00:00 2001 From: Jonathan Liu Date: Mon, 27 Dec 2010 11:59:40 +1100 Subject: QFileSystemModel: Handle QDir::NoDot and QDir::NoDotDot for setFilter Add support for QDir::NoDot and QDir::NoDotDot for setFilter in QFileSystemModel. Task-number: QTBUG-14760 Reviewed-by: Frederik --- src/gui/dialogs/qfilesystemmodel.cpp | 12 +++++---- .../auto/qfilesystemmodel/tst_qfilesystemmodel.cpp | 31 +++++++++++++++++++--- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp index cb8eb6a..ff4410d 100644 --- a/src/gui/dialogs/qfilesystemmodel.cpp +++ b/src/gui/dialogs/qfilesystemmodel.cpp @@ -1977,13 +1977,14 @@ bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) co const bool hideHidden = !(filters & QDir::Hidden); const bool hideSystem = !(filters & QDir::System); const bool hideSymlinks = (filters & QDir::NoSymLinks); - const bool hideDotAndDotDot = (filters & QDir::NoDotAndDotDot); + const bool hideDot = (filters & QDir::NoDot) || (filters & QDir::NoDotAndDotDot); // ### Qt5: simplify (because NoDotAndDotDot=NoDot|NoDotDot) + const bool hideDotDot = (filters & QDir::NoDotDot) || (filters & QDir::NoDotAndDotDot); // ### Qt5: simplify (because NoDotAndDotDot=NoDot|NoDotDot) // Note that we match the behavior of entryList and not QFileInfo on this and this // incompatibility won't be fixed until Qt 5 at least - bool isDotOrDot = ( (node->fileName == QLatin1String(".") - || node->fileName == QLatin1String(".."))); - if ( (hideHidden && (!isDotOrDot && node->isHidden())) + bool isDot = (node->fileName == QLatin1String(".")); + bool isDotDot = (node->fileName == QLatin1String("..")); + if ( (hideHidden && !(isDot || isDotDot) && node->isHidden()) || (hideSystem && node->isSystem()) || (hideDirs && node->isDir()) || (hideFiles && node->isFile()) @@ -1991,7 +1992,8 @@ bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) co || (hideReadable && node->isReadable()) || (hideWritable && node->isWritable()) || (hideExecutable && node->isExecutable()) - || (hideDotAndDotDot && isDotOrDot)) + || (hideDot && isDot) + || (hideDotDot && isDotDot)) return false; return nameFilterDisables || passNameFilters(node); diff --git a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp index 53781c9..e8d0f57 100644 --- a/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp +++ b/tests/auto/qfilesystemmodel/tst_qfilesystemmodel.cpp @@ -632,7 +632,12 @@ void tst_QFileSystemModel::filters_data() QTest::addColumn("rowCount"); #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) QTest::newRow("no dirs") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs) << QStringList() << 2; - QTest::newRow("one dir - dotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 1; + QTest::newRow("no dirs - dot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDot) << QStringList() << 1; + QTest::newRow("no dirs - dotdot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDotDot) << QStringList() << 1; + QTest::newRow("no dirs - dotanddotdot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 0; + QTest::newRow("one dir - dot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDot) << QStringList() << 2; + QTest::newRow("one dir - dotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotDot) << QStringList() << 2; + QTest::newRow("one dir - dotanddotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 1; QTest::newRow("one dir") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs) << QStringList() << 3; QTest::newRow("no dir + hidden") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::Hidden) << QStringList() << 2; QTest::newRow("dir+hid+files") << (QStringList() << "a" << "b" << "c") << QStringList() << @@ -650,7 +655,12 @@ void tst_QFileSystemModel::filters_data() #else QTest::qWait(3000); // We need to calm down a bit... QTest::newRow("no dirs") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs) << QStringList() << 0; - QTest::newRow("one dir - dotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 1; + QTest::newRow("no dirs - dot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDot) << QStringList() << 1; + QTest::newRow("no dirs - dotdot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDotDot) << QStringList() << 1; + QTest::newRow("no dirs - dotanddotdot") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 0; + QTest::newRow("one dir - dot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDot) << QStringList() << 2; + QTest::newRow("one dir - dotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotDot) << QStringList() << 2; + QTest::newRow("one dir - dotanddotdot") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs | QDir::NoDotAndDotDot) << QStringList() << 1; QTest::newRow("one dir") << (QStringList() << "a" << "b" << "c") << (QStringList() << "Z") << (int)(QDir::Dirs) << QStringList() << 1; QTest::newRow("no dir + hidden") << (QStringList() << "a" << "b" << "c") << QStringList() << (int)(QDir::Dirs | QDir::Hidden) << QStringList() << 0; QTest::newRow("dir+hid+files") << (QStringList() << "a" << "b" << "c") << QStringList() << @@ -699,10 +709,23 @@ void tst_QFileSystemModel::filters() // Make sure that we do what QDir does QDir xFactor(tmp); QDir::Filters filters = (QDir::Filters)dirFilters; + QStringList dirEntries; + if (nameFilters.count() > 0) - QCOMPARE(xFactor.entryList(nameFilters, filters).count(), rowCount); + dirEntries = xFactor.entryList(nameFilters, filters); else - QVERIFY(xFactor.entryList(filters).count() == rowCount); + dirEntries = xFactor.entryList(filters); + + QCOMPARE(dirEntries.count(), rowCount); + + QStringList modelEntries; + + for (int i = 0; i < rowCount; ++i) + modelEntries.append(model->data(model->index(i, 0, root), QFileSystemModel::FileNameRole).toString()); + + qSort(dirEntries); + qSort(modelEntries); + QCOMPARE(dirEntries, modelEntries); #ifdef Q_OS_LINUX if (files.count() >= 3 && rowCount >= 3 && rowCount != 5) { -- cgit v0.12 From d814e378987348ce2123d083b01ea6fb6c3e6bbf Mon Sep 17 00:00:00 2001 From: Pierre Rossi Date: Mon, 4 Apr 2011 15:58:42 +0200 Subject: QTableView: prevent QTableView from hanging when removing rows. The problem was introduced in cd2afafb where we removed some code that was meant to adjust the header's offset upon row removal. The problem with this is that visualIndexAt() is likely to return -1 in QHeaderView::paintEvent, which in turn will lead to calling paintSection for each and every section. Task-number: QTBUG-18551 Reviewed-by: Thierry --- src/gui/itemviews/qtableview.cpp | 21 ++++++++++++++++++++- src/gui/itemviews/qtableview.h | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp index e494ee5..59a3d15 100644 --- a/src/gui/itemviews/qtableview.cpp +++ b/src/gui/itemviews/qtableview.cpp @@ -1104,6 +1104,21 @@ void QTableView::setRootIndex(const QModelIndex &index) /*! \reimp */ +void QTableView::doItemsLayout() +{ + Q_D(QTableView); + QAbstractItemView::doItemsLayout(); + if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) + d->verticalHeader->setOffsetToSectionPosition(verticalScrollBar()->value()); + else + d->verticalHeader->setOffset(verticalScrollBar()->value()); + if (!d->verticalHeader->updatesEnabled()) + d->verticalHeader->setUpdatesEnabled(true); +} + +/*! + \reimp +*/ void QTableView::setSelectionModel(QItemSelectionModel *selectionModel) { Q_D(QTableView); @@ -1975,9 +1990,13 @@ QModelIndexList QTableView::selectedIndexes() const previous number of rows is specified by \a oldCount, and the new number of rows is specified by \a newCount. */ -void QTableView::rowCountChanged(int /*oldCount*/, int /*newCount*/ ) +void QTableView::rowCountChanged(int oldCount, int newCount ) { Q_D(QTableView); + //when removing rows, we need to disable updates for the header until the geometries have been + //updated and the offset has been adjusted, or we risk calling paintSection for all the sections + if (newCount < oldCount) + d->verticalHeader->setUpdatesEnabled(false); d->doDelayedItemsLayout(); } diff --git a/src/gui/itemviews/qtableview.h b/src/gui/itemviews/qtableview.h index d4be086..7ab9d08 100644 --- a/src/gui/itemviews/qtableview.h +++ b/src/gui/itemviews/qtableview.h @@ -71,6 +71,7 @@ public: void setModel(QAbstractItemModel *model); void setRootIndex(const QModelIndex &index); void setSelectionModel(QItemSelectionModel *selectionModel); + void doItemsLayout(); QHeaderView *horizontalHeader() const; QHeaderView *verticalHeader() const; -- cgit v0.12 From 23dd5cb45547de167f5c2e78554e9c3013e59998 Mon Sep 17 00:00:00 2001 From: Jonathan Liu Date: Tue, 5 Apr 2011 11:20:06 +0200 Subject: QTabWidget/Win: do not add content margin when documentMode enabled QTabWidget has 2 pixel bottom and right content margin. This removes the margin to maximize the area available for content and improve consistency with other Qt styles when documentMode is enabled. Task-number: QTBUG-15769 Merge-request: 957 Reviewed-by: Jens Bache-Wiig --- src/gui/styles/qwindowsxpstyle.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/gui/styles/qwindowsxpstyle.cpp b/src/gui/styles/qwindowsxpstyle.cpp index 74a20fc..4b2c3a5 100644 --- a/src/gui/styles/qwindowsxpstyle.cpp +++ b/src/gui/styles/qwindowsxpstyle.cpp @@ -1196,8 +1196,14 @@ QRect QWindowsXPStyle::subElementRect(SubElement sr, const QStyleOption *option, if (qstyleoption_cast(option)) { rect = QWindowsStyle::subElementRect(sr, option, widget); - if (sr == SE_TabWidgetTabContents) - rect.adjust(0, 0, -2, -2); + if (sr == SE_TabWidgetTabContents) { + if (const QTabWidget *tabWidget = qobject_cast(widget)) { + if (tabWidget->documentMode()) + break; + } + + rect.adjust(0, 0, -2, -2); + } } break; case SE_TabWidgetTabBar: { -- cgit v0.12 From 76a2a3278107d2713e6d999cf82db4e134c3d034 Mon Sep 17 00:00:00 2001 From: Pierre Rossi Date: Tue, 5 Apr 2011 16:30:58 +0200 Subject: Fix autotest breakage in QTableWidget Reviewed-by: gabi --- tests/auto/qtablewidget/tst_qtablewidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/qtablewidget/tst_qtablewidget.cpp b/tests/auto/qtablewidget/tst_qtablewidget.cpp index d17e064..baa99ea 100644 --- a/tests/auto/qtablewidget/tst_qtablewidget.cpp +++ b/tests/auto/qtablewidget/tst_qtablewidget.cpp @@ -1471,6 +1471,8 @@ void tst_QTableWidget::task219380_removeLastRow() testWidget->removeRow(19); //we remove the last row + QApplication::processEvents(); // See QTBUG-18551 and its fix + //we make sure the editor is at the cell position QCOMPARE(testWidget->cellWidget(18, 0)->geometry(), testWidget->visualItemRect(&item)); } -- cgit v0.12 From 45f2e655b22cb6e845183a1090fb888c32c516b3 Mon Sep 17 00:00:00 2001 From: David Boddie Date: Tue, 5 Apr 2011 20:11:00 +0200 Subject: Aim to fix Windows builds. --- doc/doc.pri | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/doc.pri b/doc/doc.pri index 68d729b..253e1b4 100644 --- a/doc/doc.pri +++ b/doc/doc.pri @@ -13,12 +13,14 @@ win32:!win32-g++* { unixstyle = true } +COPYWEBKITGUIDE = $$QT_SOURCE_TREE/examples/webkit/webkit-guide + $$unixstyle { QDOC = cd $$QT_SOURCE_TREE/tools/qdoc3/test && QT_BUILD_TREE=$$QT_BUILD_TREE QT_SOURCE_TREE=$$QT_SOURCE_TREE $$QT_BUILD_TREE/bin/qdoc3 $$DOCS_GENERATION_DEFINES - COPYWEBKITGUIDE = $$QT_SOURCE_TREE/examples/webkit/webkit-guide } else { QDOC = cd $$QT_SOURCE_TREE/tools/qdoc3/test && set QT_BUILD_TREE=$$QT_BUILD_TREE&& set QT_SOURCE_TREE=$$QT_SOURCE_TREE&& $$QT_BUILD_TREE/bin/qdoc3.exe $$DOCS_GENERATION_DEFINES QDOC = $$replace(QDOC, "/", "\\") + COPYWEBKITGUIDE = $$replace(COPYWEBKITGUIDE, "/", "\\") } ADP_DOCS_QDOCCONF_FILE = qt-build-docs-online.qdocconf QT_DOCUMENTATION = ($$QDOC qt-api-only.qdocconf assistant.qdocconf designer.qdocconf \ -- cgit v0.12 From c772ab261c3a09fab786306c70796c3c5f0efb15 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 6 Apr 2011 10:09:46 +0200 Subject: qdoc: Fixed QTBUG-18591 --- tools/qdoc3/htmlgenerator.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 114db26..88bc3e2 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -1494,8 +1494,10 @@ void HtmlGenerator::generateFakeNode(const FakeNode *fake, CodeMarker *marker) QString allQmlMembersLink = generateAllQmlMembersFile(qml_cn, marker); if (!allQmlMembersLink.isEmpty()) { + out() << "\n"; } s = sections.begin(); -- cgit v0.12 From d1b26ff2182d5a2b943ef85c406570c45781ae03 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Wed, 6 Apr 2011 12:23:13 +0200 Subject: Doc: removed documentation of a no longer used attribute --- doc/src/platforms/platform-notes.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/platforms/platform-notes.qdoc b/doc/src/platforms/platform-notes.qdoc index 88e5ae9..bb05c92 100644 --- a/doc/src/platforms/platform-notes.qdoc +++ b/doc/src/platforms/platform-notes.qdoc @@ -612,7 +612,7 @@ Qt::WA_MacNormalSize, Qt::WA_MacSmallSize, Qt::WA_MacMiniSize, Qt::WA_MacVariableSize, Qt::WA_MacBrushedMetal, Qt::WA_MacAlwaysShowToolWindow, Qt::WA_MacFrameworkScaled, Qt::WA_MacNoShadow, Qt::Sheet, Qt::Drawer, Qt::MacWindowToolBarButtonHint, - QMainWindow::unifiedTitleAndToolBarOnMac, WA_MacNoCocoaChildWindow + QMainWindow::unifiedTitleAndToolBarOnMac \section2 Mixing Qt with native code Two classes are awailable for either adding native Cocoa views/controls -- cgit v0.12 From 1db38c5ccb6188889bac1ae5e6f1d415a59ac444 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 6 Apr 2011 12:45:44 +0200 Subject: qdoc: Updated the QDoc manual. --- tools/qdoc3/ditaxmlgenerator.cpp | 24 ++++++++++++------------ tools/qdoc3/doc/corefeatures.qdoc | 8 ++++++++ tools/qdoc3/doc/qdoc-manual.qdoc | 15 +++------------ 3 files changed, 23 insertions(+), 24 deletions(-) create mode 100644 tools/qdoc3/doc/corefeatures.qdoc diff --git a/tools/qdoc3/ditaxmlgenerator.cpp b/tools/qdoc3/ditaxmlgenerator.cpp index 1bc4992..69afde9 100644 --- a/tools/qdoc3/ditaxmlgenerator.cpp +++ b/tools/qdoc3/ditaxmlgenerator.cpp @@ -5664,29 +5664,29 @@ QString DitaXmlGenerator::metadataDefault(DitaTag t) const \list \o * \o * - \o + \o not used \o * \o * \o * \o * - \o + \o not used \o * - \o - \o - \o + \o not used + \o not used + \o not used \o * - \o + \o * \o * - \o + \o not used \o * \o * \o * \o * - \o - \o - \o - \o - \o + \o not used + \o not used + \o not used + \o not used + \o not used \o * \o * \endlist diff --git a/tools/qdoc3/doc/corefeatures.qdoc b/tools/qdoc3/doc/corefeatures.qdoc new file mode 100644 index 0000000..50bd726 --- /dev/null +++ b/tools/qdoc3/doc/corefeatures.qdoc @@ -0,0 +1,8 @@ +/*! + \page corefeatures.html + \title Core Features + + \input examples/signalandslots.qdocinc + \input examples/objectmodel.qdocinc + \input examples/layoutmanagement.qdocinc +*/ diff --git a/tools/qdoc3/doc/qdoc-manual.qdoc b/tools/qdoc3/doc/qdoc-manual.qdoc index 0e4055b..5b15fca 100644 --- a/tools/qdoc3/doc/qdoc-manual.qdoc +++ b/tools/qdoc3/doc/qdoc-manual.qdoc @@ -3999,20 +3999,11 @@ Here are links to the \c .qdocinc files used above: \l{signalandslots.qdocinc}, \l{objectmodel.qdocinc}, - \l{layoutmanagement.qdocinc}. QDoc renders this page as: - - \quotation - \raw HTML -

Core Features

- \endraw - - \input examples/signalandslots.qdocinc - \input examples/objectmodel.qdocinc - \input examples/layoutmanagement.qdocinc - \endquotation + \l{layoutmanagement.qdocinc}. QDoc renders this page + \l{corefeatures.html} {as shown here}. \target 2-argument-form} - \section2 \\include filename snippet-identifier + \section2 \\include filename snippet-identifier \span {class="newStuff"} {(new)} It is kind of a pain to make a separate \c .qdocinc file for every QDoc include snippet you want to use in multiple places in the -- cgit v0.12 From 05e46b93ccb2334ec3722cf1205058f778d11458 Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig Date: Wed, 6 Apr 2011 14:35:36 +0200 Subject: Fix progressbar animation on Vista This fixes two issues. - The indeterminate animation was sometimes incorrectly disabled when value was 0 - The progress animation was incorrectly stopped when progress bars were disabled Task-number: QTBUG-10957 Reviewed-by: richard --- src/gui/styles/qwindowsvistastyle.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/gui/styles/qwindowsvistastyle.cpp b/src/gui/styles/qwindowsvistastyle.cpp index 7f1a3ab..123741e 100644 --- a/src/gui/styles/qwindowsvistastyle.cpp +++ b/src/gui/styles/qwindowsvistastyle.cpp @@ -969,7 +969,8 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption if (const QStyleOptionButton *btn = qstyleoption_cast(option)) { - if (QWindowsVistaAnimation *anim = d->widgetAnimation(widget)) { + QWindowsVistaAnimation *anim = d->widgetAnimation(widget); + if (anim && (btn->state & State_Enabled)) { anim->paint(painter, option); } else { name = QLatin1String("BUTTON"); @@ -996,7 +997,6 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption !(state & (State_Sunken | State_On)) && !(state & State_MouseOver) && (state & State_Enabled) && (state & State_Active)) { - QWindowsVistaAnimation *anim = d->widgetAnimation(widget); if (!anim && widget) { QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied); startImage.fill(0); @@ -1074,8 +1074,8 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption } if (const QProgressBar *progressbar = qobject_cast(widget)) { - if (((progressbar->value() > 0 && d->transitionsEnabled()) || isIndeterminate)) { - if (!d->widgetAnimation(progressbar) && progressbar->value() < progressbar->maximum()) { + if (isIndeterminate || (progressbar->value() > 0 && (progressbar->value() < progressbar->maximum()) && d->transitionsEnabled())) { + if (!d->widgetAnimation(progressbar)) { QWindowsVistaAnimation *a = new QWindowsVistaAnimation; a->setWidget(const_cast(widget)); a->setStartTime(QTime::currentTime()); @@ -2502,7 +2502,6 @@ void QWindowsVistaStylePrivate::timerEvent() animations[i]->widget()->update(); if (!animations[i]->widget() || - !animations[i]->widget()->isEnabled() || !animations[i]->widget()->isVisible() || animations[i]->widget()->window()->isMinimized() || !animations[i]->running() || -- cgit v0.12 From 90de2bb100b2f4a23655b2e914b93c644f1a4841 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Thu, 7 Apr 2011 09:59:57 +0200 Subject: qdoc: Updated the QDoc manual. --- src/gui/kernel/qwidget.cpp | 2 +- tools/qdoc3/doc/qdoc-manual.qdoc | 165 ++++++++++++++++++++++++++++++--------- 2 files changed, 128 insertions(+), 39 deletions(-) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index ac35d42..9d9cd75 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -598,7 +598,7 @@ void QWidget::setAutoFillBackground(bool enabled) \brief The QWidget class is the base class of all user interface objects. \ingroup basicwidgets - + The widget is the atom of the user interface: it receives mouse, keyboard and other events from the window system, and paints a representation of itself on the screen. Every widget is rectangular, and they are sorted in a diff --git a/tools/qdoc3/doc/qdoc-manual.qdoc b/tools/qdoc3/doc/qdoc-manual.qdoc index 5b15fca..31c56a1 100644 --- a/tools/qdoc3/doc/qdoc-manual.qdoc +++ b/tools/qdoc3/doc/qdoc-manual.qdoc @@ -66,6 +66,7 @@ \o \l {Compatibility Issues} \o \l {qt.qdocconf} \o \l {minimum.qdocconf} + \o \l {Generating DITA XML Output} \endlist \endlist @@ -4037,48 +4038,77 @@ sent to the QDoc input stream. You can even nest these snippets, although it's not clear why you would want to do that. - \target meta-command + \target meta-command \section1 \\meta - The \\meta command is the QDoc equivalent to the HTML - \c meta tag. + The \\meta command is mainly used for including metadata in DITA + XML files. It is also used when generating HTML output for specifying + the \e maintainer(s) of a C++ class. - The command accepts two arguments: The first argument (the - following word) is equivalent to the HTML meta tag's \e name - variable, and the second argument (the rest of the line) is - equivalent to the tag's \e contents variable. + The command has two arguments: The first argument is the name of the + metadata attribute you wish to set, and the second argument is the + value for the attribute. Each argument should be enclosed in curly + brackets, as shown in this example: - \code - / *! - \meta author Summerfield - - \section1 Automatic Dialogs - - \abstract - This article shows how to maintain sets of - "attributes" (QVariant values), and how to allow - users to view and edit them using dialogs that are - created dynamically based on the attributes and - their types. - \endabstract - - The Attributes class described in this article holds a - set of QVariants, and can create a dialog to present - the QVariants to the user in an appropriate way. - - ... - * / - \endcode - - QDoc renders this as: + \code + / *! + \class QWidget + \brief The QWidget class is the base class of all user interface objects. + + \ingroup basicwidgets + + \meta {technology} {User Interface} + \meta {platform} {OS X 10.6} + \meta {platform} {Symbian} + \meta {platform} {MeeGo} + \meta {audience} {user} + \meta {audience} {programmer} + \meta {audience} {designer} + * / + \endcode - \code - - ... - - ... - - \endcode + When running QDoc to generate HTML, the example above will have no + effect on the generated output, but if you run QDoc to generate + DITA XML, the example will generate the following: + + \code + + + + + QWidget + the QWidget class is the base class of all user interface objects. + + Qt Development Frameworks + Nokia + + + Nokia + + + + + + + Class reference + + Qt Reference Documentation + + + + QtGui + + + + + + + + \endcode + + In the example output, several values have been set using defualt + values obtained from the QDoc configuration file. See \l + {Generating DITA XML Output} for details. \target omit-command \section1 \\omit @@ -6923,7 +6953,7 @@ \page 21-1-minimum-qdocconf.html \previouspage qt.qdocconf \contentspage Table of Contents - \nextpage Table of Contents + \nextpage Generating DITA XML Output \title minimum.qdocconf @@ -6942,6 +6972,65 @@ */ /*! + \page 21-3-qt-dita-xml-output.html + \previouspage minimum.qdocconf + \contentspage Table of Contents + \nextpage Table of Contents + + \title Generating DITA XML Output + + QDoc can generate \l {http://dita.xml.org} {DITA XML output}. + + In your confifiguration file, set your \c {outputformats} variable + to \c {DITAXML}, and send the output to an appropriate directory: + + \code + outputdir = $QTDIR/doc/ditaxml + outputformats = DITAXML + \endcode + + And include these macros in your configuration file to prevent + QDoc from doing some escaping that doesn't validate in XML: + + \code + macro.aacute.DITAXML = "á" + macro.Aring.DITAXML = "Å" + macro.aring.DITAXML = "å" + macro.Auml.DITAXML = "Ä" + macro.br.DITAXML = " " + macro.BR.DITAXML = " " + macro.copyright.DITAXML = "©" + macro.eacute.DITAXML = "é" + macro.hr.DITAXML = " " + macro.iacute.DITAXML = "í" + macro.oslash.DITAXML = "ø" + macro.ouml.DITAXML = "ö" + macro.raisedaster.DITAXML = "*" + macro.rarrow.DITAXML = "→" + macro.reg.DITAXML = "®" + macro.uuml.DITAXML = "ü" + macro.mdash.DITAXML = "—" + macro.emptyspan.DITAXML = " " + \endcode + + You can also set default values for some of the tags in the DITA + \c {} and \c {} elements: + + \code + dita.metadata.default.author = Qt Development Frameworks + dita.metadata.default.permissions = all + dita.metadata.default.publisher = Nokia + dita.metadata.default.copyryear = 2011 + dita.metadata.default.copyrholder = Nokia + dita.metadata.default.audience = programmer + \endcode + + See the \l {12-0-qdoc-commands-miscellaneous.html#meta-command} + {\\meta} command for more details on DITA metadata. + +*/ + +/*! \page 22-qdoc-configuration-generalvariables.html \previouspage The QDoc Configuration File \contentspage Table of Contents -- cgit v0.12 From 58e28ff518ee983f6af0e8937bbd355a2587c4d3 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Thu, 7 Apr 2011 11:47:40 +0200 Subject: qdoc: Updated the QDoc manual. --- tools/qdoc3/doc/qdoc-manual.qdoc | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/tools/qdoc3/doc/qdoc-manual.qdoc b/tools/qdoc3/doc/qdoc-manual.qdoc index 31c56a1..9039296 100644 --- a/tools/qdoc3/doc/qdoc-manual.qdoc +++ b/tools/qdoc3/doc/qdoc-manual.qdoc @@ -7560,23 +7560,26 @@ \target macro-variable \section1 macro - The \c macro variable can be used to create your own QDoc - commands. - - The general syntax is \tt {macro.\e{command} = - "\e{definition}}". The definition can be described using QDoc - syntax. In addition it is possible to provide an HTML definition - by appending .HTML to the variable. + The \c macro variable is used to create your own simple QDoc + commands or to redefine existing QDoc commands. The syntax is \tt + {macro.\e{command} = \e{definition}}, where the definition is + written using QDoc syntax. - For example in \l qt.qdocconf: + A macro command can be restricted for use in one type of output + generation. By appending \c {.HTML} to the macro name, for + example, the macro is only used when generating HTML output. By + appending \c {.DITAXML} to the macro name, the macro is only used + when generating DITA XML. \code macro.gui = "\\bold" macro.raisedaster.HTML = "*" \endcode - makes sure that the \\gui command renders its argument using a - bold font, and that \\raisedaster renders a '*'. + The first macro defines the \\gui command to render its argument + using a bold font. The second macro defines the \\raisedaster + command to render a superscript asterisk, but only when generating + HTML. \target naturallanguage-variable \section1 naturallanguage -- cgit v0.12 From bd0f7729ad5371b3b0ba42976451b622b1209b45 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Thu, 7 Apr 2011 13:21:25 +0200 Subject: qdoc: Updated the QDoc manual. --- tools/qdoc3/doc/qdoc-manual.qdoc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/qdoc3/doc/qdoc-manual.qdoc b/tools/qdoc3/doc/qdoc-manual.qdoc index 9039296..da0646e 100644 --- a/tools/qdoc3/doc/qdoc-manual.qdoc +++ b/tools/qdoc3/doc/qdoc-manual.qdoc @@ -7061,7 +7061,7 @@ information see the \l {Compatibility Issues} {compatibility section}. - See also \l {macro-command} {macro}. + See also \l {macro-variable} {macro}. \target codeindent-variable \section1 codeindent @@ -7561,11 +7561,10 @@ \section1 macro The \c macro variable is used to create your own simple QDoc - commands or to redefine existing QDoc commands. The syntax is \tt - {macro.\e{command} = \e{definition}}, where the definition is - written using QDoc syntax. + commands. The syntax is \tt {macro.\e{command} = \e{definition}}, + where the definition is written using QDoc syntax. - A macro command can be restricted for use in one type of output + A macro variable can be restricted for use in one type of output generation. By appending \c {.HTML} to the macro name, for example, the macro is only used when generating HTML output. By appending \c {.DITAXML} to the macro name, the macro is only used @@ -7581,6 +7580,8 @@ command to render a superscript asterisk, but only when generating HTML. + See also \l {alias-variable} {alias}. + \target naturallanguage-variable \section1 naturallanguage -- cgit v0.12 From 779a58513f0c2d4e55410aee4cae6a6510841d57 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Thu, 7 Apr 2011 13:51:45 +0200 Subject: qdoc: Added missing copyright notice --- tools/qdoc3/doc/corefeatures.qdoc | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tools/qdoc3/doc/corefeatures.qdoc b/tools/qdoc3/doc/corefeatures.qdoc index 50bd726..ff903f8 100644 --- a/tools/qdoc3/doc/corefeatures.qdoc +++ b/tools/qdoc3/doc/corefeatures.qdoc @@ -1,3 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + /*! \page corefeatures.html \title Core Features -- cgit v0.12 From 384679ff46d2f970de3010fd6aac8a697dbfb907 Mon Sep 17 00:00:00 2001 From: David Boddie Date: Thu, 7 Apr 2011 19:25:06 +0200 Subject: Ensured that incomplete downloads are removed. Task-number: QTBUG-18509 --- doc/src/examples/ftp.qdoc | 4 +++- examples/network/qftp/ftpwindow.cpp | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/src/examples/ftp.qdoc b/doc/src/examples/ftp.qdoc index 4fa2cfd..841d298 100644 --- a/doc/src/examples/ftp.qdoc +++ b/doc/src/examples/ftp.qdoc @@ -131,7 +131,9 @@ \snippet examples/network/qftp/ftpwindow.cpp 5 - QFtp supports canceling the download of files. + QFtp supports canceling the download of files. We make sure that + any file that is currently being written to is closed and removed, + and tidy up by deleting the file object. \snippet examples/network/qftp/ftpwindow.cpp 6 diff --git a/examples/network/qftp/ftpwindow.cpp b/examples/network/qftp/ftpwindow.cpp index c3e629f..159cad6 100644 --- a/examples/network/qftp/ftpwindow.cpp +++ b/examples/network/qftp/ftpwindow.cpp @@ -243,6 +243,12 @@ void FtpWindow::downloadFile() void FtpWindow::cancelDownload() { ftp->abort(); + + if (file->exists()) { + file->close(); + file->remove(); + } + delete file; } //![5] -- cgit v0.12 From 932b28483f82f3fbc3a007ecdc5fbb152b504024 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Fri, 8 Apr 2011 08:05:55 +0200 Subject: qdoc: Fixed license comment. --- tools/qdoc3/doc/corefeatures.qdoc | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/tools/qdoc3/doc/corefeatures.qdoc b/tools/qdoc3/doc/corefeatures.qdoc index ff903f8..ee579cf 100644 --- a/tools/qdoc3/doc/corefeatures.qdoc +++ b/tools/qdoc3/doc/corefeatures.qdoc @@ -4,37 +4,23 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the tools applications of the Qt Toolkit. +** This file is part of the documentation of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $QT_BEGIN_LICENSE:FDL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ -- cgit v0.12 From a5d40fd3814ab7c8e865912c03a918bfd5994998 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Mon, 11 Apr 2011 12:56:56 +0200 Subject: Switch the default graphics system to raster on Mac. Reviewed-by: Lars Knoll --- src/gui/painting/qgraphicssystemfactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/painting/qgraphicssystemfactory.cpp b/src/gui/painting/qgraphicssystemfactory.cpp index 62a60d7..6212674 100644 --- a/src/gui/painting/qgraphicssystemfactory.cpp +++ b/src/gui/painting/qgraphicssystemfactory.cpp @@ -74,7 +74,7 @@ QGraphicsSystem *QGraphicsSystemFactory::create(const QString& key) if (system.isEmpty()) { system = QLatin1String("runtime"); } -#elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) && !defined(Q_OS_SYMBIAN) || defined(Q_WS_X11) +#elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) && !defined(Q_OS_SYMBIAN) || defined(Q_WS_X11) || (defined (Q_WS_MAC) && defined(QT_MAC_USE_COCOA)) if (system.isEmpty()) { system = QLatin1String("raster"); } -- cgit v0.12 From a769192ef0393afa07c08a1672b45604fdf64be1 Mon Sep 17 00:00:00 2001 From: David Boddie Date: Mon, 11 Apr 2011 15:44:03 +0200 Subject: Doc: Fixed reference to a name in a table. Task-number: QTBUG-18679 --- src/gui/itemviews/qdatawidgetmapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/itemviews/qdatawidgetmapper.cpp b/src/gui/itemviews/qdatawidgetmapper.cpp index 745ef5a..dac4613 100644 --- a/src/gui/itemviews/qdatawidgetmapper.cpp +++ b/src/gui/itemviews/qdatawidgetmapper.cpp @@ -291,7 +291,7 @@ void QDataWidgetMapperPrivate::_q_modelDestroyed() \snippet doc/src/snippets/code/src_gui_itemviews_qdatawidgetmapper.cpp 0 After the call to toFirst(), \c mySpinBox displays the value \c{1}, \c myLineEdit - displays \c {Nokia Corporation and/or its subsidiary(-ies)} and \c myCountryChooser displays \c{Oslo}. The + displays \c{Qt Norway} and \c myCountryChooser displays \c{Oslo}. The navigational functions toFirst(), toNext(), toPrevious(), toLast() and setCurrentIndex() can be used to navigate in the model and update the widgets with contents from the model. -- cgit v0.12 From 5b3872b2d7523d44ba454a76613e7a3fa45387f7 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Mon, 11 Apr 2011 16:52:59 +0200 Subject: Fixed a crash in QListView The problem was that QAbstractScrollArea calls layoutChildren on resize but the QListView requires that updateGeometries is called before. Task: QTBUG-18558 Reviewed-By: Pierre --- src/gui/itemviews/qabstractitemview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 081a6d9..5142107 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -1542,6 +1542,7 @@ bool QAbstractItemView::event(QEvent *event) break; case QEvent::LayoutDirectionChange: case QEvent::ApplicationLayoutDirectionChange: + case QEvent::Resize: updateGeometries(); break; case QEvent::StyleChange: @@ -2396,7 +2397,6 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) void QAbstractItemView::resizeEvent(QResizeEvent *event) { QAbstractScrollArea::resizeEvent(event); - updateGeometries(); } /*! -- cgit v0.12 From 0848b860b9251e76b9319f65554f932ab68e33cc Mon Sep 17 00:00:00 2001 From: Pierre Rossi Date: Thu, 6 Jan 2011 22:09:48 +0100 Subject: Calculate the submenu position after emitting aboutToShow() The rationale behind this is that if the submenu gets populated in a slot connected to aboutToShow(), we'll have to do it again anyway. Task-number: QTBUG-14739 Reviewed-by: Thierry --- src/gui/widgets/qmenu.cpp | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index c09b5a4..d4f6c61 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -351,7 +351,6 @@ void QMenuPrivate::updateActionRects() const const int min_column_width = q->minimumWidth() - (sfcMargin + leftmargin + rightmargin + 2 * (fw + hmargin)); max_column_width = qMax(min_column_width, max_column_width); - //calculate position const int base_y = vmargin + fw + topmargin + (scroll ? scroll->scrollOffset : 0) + @@ -1931,6 +1930,27 @@ void QMenu::popup(const QPoint &p, QAction *atAction) } } } + const int subMenuOffset = style()->pixelMetric(QStyle::PM_SubMenuOverlap, 0, this); + const QSize menuSize(sizeHint()); + QMenu *caused = qobject_cast(d_func()->causedPopup.widget); + if (caused && caused->geometry().width() + menuSize.width() + subMenuOffset < screen.width()) { + QRect parentActionRect(caused->d_func()->actionRect(caused->d_func()->currentAction)); + const QPoint actionTopLeft = caused->mapToGlobal(parentActionRect.topLeft()); + parentActionRect.moveTopLeft(actionTopLeft); + if (isRightToLeft()) { + if ((pos.x() + menuSize.width() > parentActionRect.left() - subMenuOffset) + && (pos.x() < parentActionRect.right())) + { + pos.rx() = parentActionRect.right(); + } + } else { + if ((pos.x() < parentActionRect.right() + subMenuOffset) + && (pos.x() + menuSize.width() > parentActionRect.left())) + { + pos.rx() = parentActionRect.left() - menuSize.width(); + } + } + } setGeometry(QRect(pos, size)); #ifndef QT_NO_EFFECTS int hGuess = isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll; @@ -2963,28 +2983,8 @@ void QMenu::internalDelayedPopup() const QRect actionRect(d->actionRect(d->currentAction)); const QSize menuSize(d->activeMenu->sizeHint()); const QPoint rightPos(mapToGlobal(QPoint(actionRect.right() + subMenuOffset + 1, actionRect.top()))); - const QPoint leftPos(mapToGlobal(QPoint(actionRect.left() - subMenuOffset - menuSize.width(), actionRect.top()))); QPoint pos(rightPos); - QMenu *caused = qobject_cast(d->activeMenu->d_func()->causedPopup.widget); - - const QRect availGeometry(d->popupGeometry(caused)); - if (isRightToLeft()) { - pos = leftPos; - if ((caused && caused->x() < x()) || pos.x() < availGeometry.left()) { - if(rightPos.x() + menuSize.width() < availGeometry.right()) - pos = rightPos; - else - pos.rx() = availGeometry.left(); - } - } else { - if ((caused && caused->x() > x()) || pos.x() + menuSize.width() > availGeometry.right()) { - if(leftPos.x() < availGeometry.left()) - pos.rx() = availGeometry.right() - menuSize.width(); - else - pos = leftPos; - } - } //calc sloppy focus buffer if (style()->styleHint(QStyle::SH_Menu_SloppySubMenus, 0, this)) { -- cgit v0.12 From b10265efba544b1e4820f45b86354d442f6abf26 Mon Sep 17 00:00:00 2001 From: Pierre Rossi Date: Mon, 10 Jan 2011 18:46:19 +0100 Subject: Fix a bug with menu overflowing from a lower resolution second screen. The menu needs to take into account the screen geometry of the screen it's about to be shown on (not the last screen it was shown on) when updating its actions rects Task-number: QTBUG-2748 Reviewed-by: Thierry --- src/gui/widgets/qmenu.cpp | 61 +++++++++++++++++++++++++++++++++++++---------- src/gui/widgets/qmenu_p.h | 4 +++- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index d4f6c61..56b9e24 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -228,6 +228,12 @@ QList > QMenuPrivate::calcCausedStack() const void QMenuPrivate::updateActionRects() const { Q_Q(const QMenu); + updateActionRects(popupGeometry(q)); +} + +void QMenuPrivate::updateActionRects(const QRect &screen) const +{ + Q_Q(const QMenu); if (!itemsDirty) return; @@ -237,20 +243,10 @@ void QMenuPrivate::updateActionRects() const actionRects.resize(actions.count()); actionRects.fill(QRect()); - //let's try to get the last visible action - int lastVisibleAction = actions.count() - 1; - for(;lastVisibleAction >= 0; --lastVisibleAction) { - const QAction *action = actions.at(lastVisibleAction); - if (action->isVisible()) { - //removing trailing separators - if (action->isSeparator() && collapsibleSeparators) - continue; - break; - } - } + int lastVisibleAction = getLastVisibleAction(); int max_column_width = 0, - dh = popupGeometry(q).height(), + dh = screen.height(), y = 0; QStyle *style = q->style(); QStyleOption opt; @@ -381,6 +377,34 @@ void QMenuPrivate::updateActionRects() const itemsDirty = 0; } +QSize QMenuPrivate::adjustMenuSizeForScreen(const QRect &screen) +{ + Q_Q(QMenu); + QSize ret = screen.size(); + itemsDirty = true; + updateActionRects(screen); + const int fw = q->style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q); + ret.setWidth(actionRects.at(getLastVisibleAction()).right() + fw); + return ret; +} + +int QMenuPrivate::getLastVisibleAction() const +{ + //let's try to get the last visible action + int lastVisibleAction = actions.count() - 1; + for (;lastVisibleAction >= 0; --lastVisibleAction) { + const QAction *action = actions.at(lastVisibleAction); + if (action->isVisible()) { + //removing trailing separators + if (action->isSeparator() && collapsibleSeparators) + continue; + break; + } + } + return lastVisibleAction; +} + + QRect QMenuPrivate::actionRect(QAction *act) const { int index = actions.indexOf(act); @@ -1834,9 +1858,20 @@ void QMenu::popup(const QPoint &p, QAction *atAction) else #endif screen = d->popupGeometry(QApplication::desktop()->screenNumber(p)); - const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this); bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen); + + // if the screens have very different geometries and the menu is too big, we have to recalculate + if (size.height() > screen.height() || size.width() > screen.width()) { + size = d->adjustMenuSizeForScreen(screen); + adjustToDesktop = true; + } + // Layout is not right, we might be able to save horizontal space + if (d->ncols >1 && size.height() < screen.height()) { + size = d->adjustMenuSizeForScreen(screen); + adjustToDesktop = true; + } + #ifdef QT_KEYPAD_NAVIGATION if (!atAction && QApplication::keypadNavigationEnabled()) { // Try to have one item activated diff --git a/src/gui/widgets/qmenu_p.h b/src/gui/widgets/qmenu_p.h index b6efde3..005ce1d 100644 --- a/src/gui/widgets/qmenu_p.h +++ b/src/gui/widgets/qmenu_p.h @@ -194,10 +194,13 @@ public: mutable QVector actionRects; mutable QHash widgetItems; void updateActionRects() const; + void updateActionRects(const QRect &screen) const; QRect popupGeometry(const QWidget *widget) const; QRect popupGeometry(int screen = -1) const; mutable uint ncols : 4; //4 bits is probably plenty uint collapsibleSeparators : 1; + QSize adjustMenuSizeForScreen(const QRect & screen); + int getLastVisibleAction() const; bool activationRecursionGuard; @@ -296,7 +299,6 @@ public: void updateLayoutDirection(); - //menu fading/scrolling effects bool doChildEffects; -- cgit v0.12 From e89a2b72050dd782da16ff24bc2eb84dc36ed6a5 Mon Sep 17 00:00:00 2001 From: Jonathan Liu Date: Tue, 12 Apr 2011 13:55:46 +0200 Subject: Fix incorrect rendering of checked menu items on Windows Classic Modify rendering of checked menu items when using Windows Classic style to be more native looking. Changes: * Checked menu items with no icon are not drawn sunken * Disabled checked menu items with an icon have a plain background instead of a checkerboard pattern same as when enabled * Check mark is drawn with highlighted text color when selected to match text * Fix check mark offset for disabled unselected checked menu item as the entire check mark was drawn shifted (1, 1) * Fix color of check mark shadow for disabled unselected checked menu item as it was same color as the check mark when it should be a light color Task-number: QTBUG-15098 Merge-request: 2513 Reviewed-by: Jens Bache-Wiig --- src/gui/styles/qcommonstyle.cpp | 13 +++++-------- src/gui/styles/qwindowsstyle.cpp | 4 ++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/gui/styles/qcommonstyle.cpp b/src/gui/styles/qcommonstyle.cpp index 8f99d6a..3d04c9a 100644 --- a/src/gui/styles/qcommonstyle.cpp +++ b/src/gui/styles/qcommonstyle.cpp @@ -223,16 +223,13 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q --yy; } if (!(opt->state & State_Enabled) && !(opt->state & State_On)) { - int pnt; - p->setPen(opt->palette.highlightedText().color()); - QPoint offset(1, 1); - for (pnt = 0; pnt < a.size(); ++pnt) - a[pnt].translate(offset.x(), offset.y()); + p->save(); + p->translate(1, 1); + p->setPen(opt->palette.light().color()); p->drawLines(a); - for (pnt = 0; pnt < a.size(); ++pnt) - a[pnt].translate(offset.x(), offset.y()); + p->restore(); } - p->setPen(opt->palette.text().color()); + p->setPen((opt->state & State_On) ? opt->palette.highlightedText().color() : opt->palette.text().color()); p->drawLines(a); break; } case PE_Frame: diff --git a/src/gui/styles/qwindowsstyle.cpp b/src/gui/styles/qwindowsstyle.cpp index 44f3f92..1dcfd00 100644 --- a/src/gui/styles/qwindowsstyle.cpp +++ b/src/gui/styles/qwindowsstyle.cpp @@ -1858,8 +1858,8 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai } QRect vCheckRect = visualRect(opt->direction, menuitem->rect, QRect(menuitem->rect.x(), menuitem->rect.y(), checkcol, menuitem->rect.height())); - if (checked) { - if (act && !dis) { + if (!menuitem->icon.isNull() && checked) { + if (act) { qDrawShadePanel(p, vCheckRect, menuitem->palette, true, 1, &menuitem->palette.brush(QPalette::Button)); -- cgit v0.12 From abc5a632942c23496d75c49b3b0b4a674cdafdf8 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Tue, 12 Apr 2011 16:23:57 +0200 Subject: Fix a race condition when the main window is being destructed. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During the destructor of QWidget, we delete the layout. If the layout is not set to 0 afterwards, a check on the layout might turn true, but any access will end with a segfault. Reviewed-by: João Abecasis --- src/gui/kernel/qwidget.cpp | 1 + src/gui/painting/qunifiedtoolbarsurface_mac.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 5705214..758ccce 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -1588,6 +1588,7 @@ QWidget::~QWidget() // delete layout while we still are a valid widget delete d->layout; + d->layout = 0; // Remove myself from focus list Q_ASSERT(d->focus_next->d_func()->focus_prev == this); diff --git a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp index 3876c3d..2fda6b9 100644 --- a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp +++ b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp @@ -152,7 +152,8 @@ void QUnifiedToolbarSurface::beginPaint(const QRegion &rgn) void QUnifiedToolbarSurface::updateToolbarOffset(QWidget *widget) { QMainWindowLayout *mlayout = qobject_cast (widget->window()->layout()); - mlayout->updateUnifiedToolbarOffset(); + if (mlayout) + mlayout->updateUnifiedToolbarOffset(); } void QUnifiedToolbarSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) -- cgit v0.12 From b00089261eafbdf5f92ed94d7fb20b402bfcaeb2 Mon Sep 17 00:00:00 2001 From: Stephen Kelly Date: Wed, 10 Nov 2010 11:21:53 +0100 Subject: Add the QIdentityProxyModel. Older commit history is in KDE svn: http://websvn.kde.org/trunk/KDE/kdelibs/kdeui/itemviews/kidentityproxymodel.cpp?view=log Ammended to update the license headers. Merge-request: 900 Reviewed-by: Gabriel de Dietrich --- .../model-view-programming.qdoc | 7 + .../code/src_gui_itemviews_qidentityproxymodel.cpp | 66 +++ src/corelib/kernel/qabstractitemmodel.h | 1 + src/gui/itemviews/itemviews.pri | 2 + src/gui/itemviews/qidentityproxymodel.cpp | 582 +++++++++++++++++++++ src/gui/itemviews/qidentityproxymodel.h | 115 ++++ src/gui/itemviews/qsortfilterproxymodel.cpp | 2 +- tests/auto/gui.pro | 1 + tests/auto/headers/tst_headers.cpp | 4 + .../qidentityproxymodel/qidentityproxymodel.pro | 6 + .../tst_qidentityproxymodel.cpp | 329 ++++++++++++ 11 files changed, 1114 insertions(+), 1 deletion(-) create mode 100644 doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp create mode 100644 src/gui/itemviews/qidentityproxymodel.cpp create mode 100644 src/gui/itemviews/qidentityproxymodel.h create mode 100644 tests/auto/qidentityproxymodel/qidentityproxymodel.pro create mode 100644 tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp diff --git a/doc/src/frameworks-technologies/model-view-programming.qdoc b/doc/src/frameworks-technologies/model-view-programming.qdoc index 92067b9..42404b0 100644 --- a/doc/src/frameworks-technologies/model-view-programming.qdoc +++ b/doc/src/frameworks-technologies/model-view-programming.qdoc @@ -1934,6 +1934,13 @@ \l{QSortFilterProxyModel::lessThan()}{lessThan()} function to perform custom comparisons. + \section3 Custom data models + + QIdentityProxyModel instances do not sort or filter the structure of the source model, + but provide a base class for creating a data proxy. This could be useful on top of a + QFileSystemModel for example to provide different colours for the BackgroundRole for + different types of files. + \section1 Model subclassing reference Model subclasses need to provide implementations of many of the virtual functions diff --git a/doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp b/doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp new file mode 100644 index 0000000..8bd6520 --- /dev/null +++ b/doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, +** a KDAB Group company, info@kdab.com, +** author Stephen Kelly +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +class DateFormatProxyModel : public QIdentityProxyModel +{ + // ... + + void setDateFormatString(const QString &formatString) + { + m_formatString = formatString; + } + + QVariant data(const QModelIndex &index, int role) + { + if (role != Qt::DisplayRole) + return QIdentityProxyModel::data(index, role); + + const QDateTime dateTime = sourceModel()->data(SourceClass::DateRole).toDateTime(); + + return dateTime.toString(m_formatString); + } + +private: + QString m_formatString; +}; +//! [0] diff --git a/src/corelib/kernel/qabstractitemmodel.h b/src/corelib/kernel/qabstractitemmodel.h index 6de3bf5..7bed3a2 100644 --- a/src/corelib/kernel/qabstractitemmodel.h +++ b/src/corelib/kernel/qabstractitemmodel.h @@ -162,6 +162,7 @@ class Q_CORE_EXPORT QAbstractItemModel : public QObject friend class QPersistentModelIndexData; friend class QAbstractItemViewPrivate; + friend class QIdentityProxyModel; public: explicit QAbstractItemModel(QObject *parent = 0); diff --git a/src/gui/itemviews/itemviews.pri b/src/gui/itemviews/itemviews.pri index bbc1e98..149bfd6 100644 --- a/src/gui/itemviews/itemviews.pri +++ b/src/gui/itemviews/itemviews.pri @@ -4,6 +4,7 @@ HEADERS += \ itemviews/qabstractitemview.h \ itemviews/qabstractitemview_p.h \ itemviews/qheaderview.h \ + itemviews/qidentityproxymodel.h \ itemviews/qlistview.h \ itemviews/qlistview_p.h \ itemviews/qbsptree_p.h \ @@ -44,6 +45,7 @@ HEADERS += \ SOURCES += \ itemviews/qabstractitemview.cpp \ itemviews/qheaderview.cpp \ + itemviews/qidentityproxymodel.cpp \ itemviews/qlistview.cpp \ itemviews/qbsptree.cpp \ itemviews/qtableview.cpp \ diff --git a/src/gui/itemviews/qidentityproxymodel.cpp b/src/gui/itemviews/qidentityproxymodel.cpp new file mode 100644 index 0000000..9396e61 --- /dev/null +++ b/src/gui/itemviews/qidentityproxymodel.cpp @@ -0,0 +1,582 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, +** a KDAB Group company, info@kdab.com, +** author Stephen Kelly +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +****************************************************************************/ + +#include "qidentityproxymodel.h" + +#ifndef QT_NO_IDENTITYPROXYMODEL + +#include "qitemselectionmodel.h" +#include + +QT_BEGIN_NAMESPACE + +class QIdentityProxyModelPrivate : public QAbstractProxyModelPrivate +{ + QIdentityProxyModelPrivate() + : ignoreNextLayoutAboutToBeChanged(false), + ignoreNextLayoutChanged(false) + { + + } + + Q_DECLARE_PUBLIC(QIdentityProxyModel) + + bool ignoreNextLayoutAboutToBeChanged; + bool ignoreNextLayoutChanged; + QList layoutChangePersistentIndexes; + QModelIndexList proxyIndexes; + + void _q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end); + void _q_sourceRowsInserted(const QModelIndex &parent, int start, int end); + void _q_sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + void _q_sourceRowsRemoved(const QModelIndex &parent, int start, int end); + void _q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest); + void _q_sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest); + + void _q_sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end); + void _q_sourceColumnsInserted(const QModelIndex &parent, int start, int end); + void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + void _q_sourceColumnsRemoved(const QModelIndex &parent, int start, int end); + void _q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest); + void _q_sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest); + + void _q_sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last); + + void _q_sourceLayoutAboutToBeChanged(); + void _q_sourceLayoutChanged(); + void _q_sourceModelAboutToBeReset(); + void _q_sourceModelReset(); + +}; + +/*! + \since 4.8 + \class QIdentityProxyModel + \brief The QIdentityProxyModel class proxies its source model unmodified + + \ingroup model-view + + QIdentityProxyModel can be used to forward the structure of a source model exactly, with no sorting, filtering or other transformation. + This is similar in concept to an identity matrix where A.I = A. + + Because it does no sorting or filtering, this class is most suitable to proxy models which transform the data() of the source model. + For example, a proxy model could be created to define the font used, or the background colour, or the tooltip etc. This removes the + need to implement all data handling in the same class that creates the structure of the model, and can also be used to create + re-usable components. + + This also provides a way to change the data in the case where a source model is supplied by a third party which can not be modified. + + \snippet doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp 0 + + \sa QAbstractProxyModel, {Model/View Programming}, QAbstractItemModel + +*/ + +/*! + Constructs an identity model with the given \a parent. +*/ +QIdentityProxyModel::QIdentityProxyModel(QObject* parent) + : QAbstractProxyModel(*new QIdentityProxyModelPrivate, parent) +{ + +} + +/*! \internal + */ +QIdentityProxyModel::QIdentityProxyModel(QIdentityProxyModelPrivate &dd, QObject* parent) + : QAbstractProxyModel(dd, parent) +{ + +} + +/*! + Destroys this identity model. +*/ +QIdentityProxyModel::~QIdentityProxyModel() +{ +} + +/*! + \reimp + */ +int QIdentityProxyModel::columnCount(const QModelIndex& parent) const +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(const QIdentityProxyModel); + return d->model->columnCount(mapToSource(parent)); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->dropMimeData(data, action, row, column, mapToSource(parent)); +} + +/*! + \reimp + */ +QModelIndex QIdentityProxyModel::index(int row, int column, const QModelIndex& parent) const +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(const QIdentityProxyModel); + if (!hasIndex(row, column, parent)) + return QModelIndex(); + const QModelIndex sourceParent = mapToSource(parent); + const QModelIndex sourceIndex = d->model->index(row, column, sourceParent); + Q_ASSERT(sourceIndex.isValid()); + return mapFromSource(sourceIndex); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::insertColumns(int column, int count, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->insertColumns(column, count, mapToSource(parent)); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::insertRows(int row, int count, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->insertRows(row, count, mapToSource(parent)); +} + +/*! + \reimp + */ +QModelIndex QIdentityProxyModel::mapFromSource(const QModelIndex& sourceIndex) const +{ + Q_D(const QIdentityProxyModel); + if (!d->model || !sourceIndex.isValid()) + return QModelIndex(); + + Q_ASSERT(sourceIndex.model() == d->model); + return createIndex(sourceIndex.row(), sourceIndex.column(), sourceIndex.internalPointer()); +} + +/*! + \reimp + */ +QItemSelection QIdentityProxyModel::mapSelectionFromSource(const QItemSelection& selection) const +{ + Q_D(const QIdentityProxyModel); + QItemSelection proxySelection; + + if (!d->model) + return proxySelection; + + QItemSelection::const_iterator it = selection.constBegin(); + const QItemSelection::const_iterator end = selection.constEnd(); + for ( ; it != end; ++it) { + Q_ASSERT(it->model() == d->model); + const QItemSelectionRange range(mapFromSource(it->topLeft()), mapFromSource(it->bottomRight())); + proxySelection.append(range); + } + + return proxySelection; +} + +/*! + \reimp + */ +QItemSelection QIdentityProxyModel::mapSelectionToSource(const QItemSelection& selection) const +{ + Q_D(const QIdentityProxyModel); + QItemSelection sourceSelection; + + if (!d->model) + return sourceSelection; + + QItemSelection::const_iterator it = selection.constBegin(); + const QItemSelection::const_iterator end = selection.constEnd(); + for ( ; it != end; ++it) { + Q_ASSERT(it->model() == this); + const QItemSelectionRange range(mapToSource(it->topLeft()), mapToSource(it->bottomRight())); + sourceSelection.append(range); + } + + return sourceSelection; +} + +/*! + \reimp + */ +QModelIndex QIdentityProxyModel::mapToSource(const QModelIndex& proxyIndex) const +{ + Q_D(const QIdentityProxyModel); + if (!d->model || !proxyIndex.isValid()) + return QModelIndex(); + Q_ASSERT(proxyIndex.model() == this); + return d->model->createIndex(proxyIndex.row(), proxyIndex.column(), proxyIndex.internalPointer()); +} + +/*! + \reimp + */ +QModelIndexList QIdentityProxyModel::match(const QModelIndex& start, int role, const QVariant& value, int hits, Qt::MatchFlags flags) const +{ + Q_D(const QIdentityProxyModel); + Q_ASSERT(start.isValid() ? start.model() == this : true); + if (!d->model) + return QModelIndexList(); + + const QModelIndexList sourceList = d->model->match(mapToSource(start), role, value, hits, flags); + QModelIndexList::const_iterator it = sourceList.constBegin(); + const QModelIndexList::const_iterator end = sourceList.constEnd(); + QModelIndexList proxyList; + for ( ; it != end; ++it) + proxyList.append(mapFromSource(*it)); + return proxyList; +} + +/*! + \reimp + */ +QModelIndex QIdentityProxyModel::parent(const QModelIndex& child) const +{ + Q_ASSERT(child.isValid() ? child.model() == this : true); + const QModelIndex sourceIndex = mapToSource(child); + const QModelIndex sourceParent = sourceIndex.parent(); + return mapFromSource(sourceParent); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::removeColumns(int column, int count, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->removeColumns(column, count, mapToSource(parent)); +} + +/*! + \reimp + */ +bool QIdentityProxyModel::removeRows(int row, int count, const QModelIndex& parent) +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(QIdentityProxyModel); + return d->model->removeRows(row, count, mapToSource(parent)); +} + +/*! + \reimp + */ +int QIdentityProxyModel::rowCount(const QModelIndex& parent) const +{ + Q_ASSERT(parent.isValid() ? parent.model() == this : true); + Q_D(const QIdentityProxyModel); + return d->model->rowCount(mapToSource(parent)); +} + +/*! + \reimp + */ +void QIdentityProxyModel::setSourceModel(QAbstractItemModel* sourceModel) +{ + beginResetModel(); + + if (sourceModel) { + disconnect(sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(_q_sourceRowsAboutToBeInserted(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, SLOT(_q_sourceRowsInserted(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(_q_sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, SLOT(_q_sourceRowsRemoved(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + this, SLOT(_q_sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + disconnect(sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + this, SLOT(_q_sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + disconnect(sourceModel, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(_q_sourceColumnsAboutToBeInserted(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(columnsInserted(const QModelIndex &, int, int)), + this, SLOT(_q_sourceColumnsInserted(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(_q_sourceColumnsAboutToBeRemoved(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(columnsRemoved(const QModelIndex &, int, int)), + this, SLOT(_q_sourceColumnsRemoved(const QModelIndex &, int, int))); + disconnect(sourceModel, SIGNAL(columnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + this, SLOT(_q_sourceColumnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + disconnect(sourceModel, SIGNAL(columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + this, SLOT(_q_sourceColumnsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + disconnect(sourceModel, SIGNAL(modelAboutToBeReset()), + this, SLOT(_q_sourceModelAboutToBeReset())); + disconnect(sourceModel, SIGNAL(modelReset()), + this, SLOT(_q_sourceModelReset())); + disconnect(sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + this, SLOT(_q_sourceDataChanged(const QModelIndex &, const QModelIndex &))); + disconnect(sourceModel, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), + this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int))); + disconnect(sourceModel, SIGNAL(layoutAboutToBeChanged()), + this, SLOT(_q_sourceLayoutAboutToBeChanged())); + disconnect(sourceModel, SIGNAL(layoutChanged()), + this, SLOT(_q_sourceLayoutChanged())); + } + + QAbstractProxyModel::setSourceModel(sourceModel); + + if (sourceModel) { + connect(sourceModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + SLOT(_q_sourceRowsAboutToBeInserted(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + SLOT(_q_sourceRowsInserted(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + SLOT(_q_sourceRowsAboutToBeRemoved(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + SLOT(_q_sourceRowsRemoved(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + SLOT(_q_sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + connect(sourceModel, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + SLOT(_q_sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + connect(sourceModel, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)), + SLOT(_q_sourceColumnsAboutToBeInserted(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(columnsInserted(const QModelIndex &, int, int)), + SLOT(_q_sourceColumnsInserted(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)), + SLOT(_q_sourceColumnsAboutToBeRemoved(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(columnsRemoved(const QModelIndex &, int, int)), + SLOT(_q_sourceColumnsRemoved(const QModelIndex &, int, int))); + connect(sourceModel, SIGNAL(columnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + SLOT(_q_sourceColumnsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + connect(sourceModel, SIGNAL(columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)), + SLOT(_q_sourceColumnsMoved(const QModelIndex &, int, int, const QModelIndex &, int))); + connect(sourceModel, SIGNAL(modelAboutToBeReset()), + SLOT(_q_sourceModelAboutToBeReset())); + connect(sourceModel, SIGNAL(modelReset()), + SLOT(_q_sourceModelReset())); + connect(sourceModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + SLOT(_q_sourceDataChanged(const QModelIndex &, const QModelIndex &))); + connect(sourceModel, SIGNAL(headerDataChanged(Qt::Orientation,int,int)), + SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int))); + connect(sourceModel, SIGNAL(layoutAboutToBeChanged()), + SLOT(_q_sourceLayoutAboutToBeChanged())); + connect(sourceModel, SIGNAL(layoutChanged()), + SLOT(_q_sourceLayoutChanged())); + } + + endResetModel(); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginInsertColumns(q->mapFromSource(parent), start, end); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest) +{ + Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true); + Q_ASSERT(destParent.isValid() ? destParent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginMoveColumns(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destParent), dest); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginRemoveColumns(q->mapFromSource(parent), start, end); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsInserted(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + q->endInsertColumns(); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest) +{ + Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true); + Q_ASSERT(destParent.isValid() ? destParent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(sourceParent) + Q_UNUSED(sourceStart) + Q_UNUSED(sourceEnd) + Q_UNUSED(destParent) + Q_UNUSED(dest) + q->endMoveColumns(); +} + +void QIdentityProxyModelPrivate::_q_sourceColumnsRemoved(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + q->endRemoveColumns(); +} + +void QIdentityProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) +{ + Q_ASSERT(topLeft.isValid() ? topLeft.model() == model : true); + Q_ASSERT(bottomRight.isValid() ? bottomRight.model() == model : true); + Q_Q(QIdentityProxyModel); + q->dataChanged(q->mapFromSource(topLeft), q->mapFromSource(bottomRight)); +} + +void QIdentityProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last) +{ + Q_Q(QIdentityProxyModel); + q->headerDataChanged(orientation, first, last); +} + +void QIdentityProxyModelPrivate::_q_sourceLayoutAboutToBeChanged() +{ + if (ignoreNextLayoutAboutToBeChanged) + return; + + Q_Q(QIdentityProxyModel); + + foreach(const QPersistentModelIndex &proxyPersistentIndex, q->persistentIndexList()) { + proxyIndexes << proxyPersistentIndex; + Q_ASSERT(proxyPersistentIndex.isValid()); + const QPersistentModelIndex srcPersistentIndex = q->mapToSource(proxyPersistentIndex); + Q_ASSERT(srcPersistentIndex.isValid()); + layoutChangePersistentIndexes << srcPersistentIndex; + } + + q->layoutAboutToBeChanged(); +} + +void QIdentityProxyModelPrivate::_q_sourceLayoutChanged() +{ + if (ignoreNextLayoutChanged) + return; + + Q_Q(QIdentityProxyModel); + + for (int i = 0; i < proxyIndexes.size(); ++i) { + q->changePersistentIndex(proxyIndexes.at(i), q->mapFromSource(layoutChangePersistentIndexes.at(i))); + } + + layoutChangePersistentIndexes.clear(); + proxyIndexes.clear(); + + q->layoutChanged(); +} + +void QIdentityProxyModelPrivate::_q_sourceModelAboutToBeReset() +{ + Q_Q(QIdentityProxyModel); + q->beginResetModel(); +} + +void QIdentityProxyModelPrivate::_q_sourceModelReset() +{ + Q_Q(QIdentityProxyModel); + q->endResetModel(); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginInsertRows(q->mapFromSource(parent), start, end); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest) +{ + Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true); + Q_ASSERT(destParent.isValid() ? destParent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginMoveRows(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destParent), dest); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + q->beginRemoveRows(q->mapFromSource(parent), start, end); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsInserted(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + q->endInsertRows(); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest) +{ + Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true); + Q_ASSERT(destParent.isValid() ? destParent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(sourceParent) + Q_UNUSED(sourceStart) + Q_UNUSED(sourceEnd) + Q_UNUSED(destParent) + Q_UNUSED(dest) + q->endMoveRows(); +} + +void QIdentityProxyModelPrivate::_q_sourceRowsRemoved(const QModelIndex &parent, int start, int end) +{ + Q_ASSERT(parent.isValid() ? parent.model() == model : true); + Q_Q(QIdentityProxyModel); + Q_UNUSED(parent) + Q_UNUSED(start) + Q_UNUSED(end) + q->endRemoveRows(); +} + +QT_END_NAMESPACE + +#include "moc_qidentityproxymodel.cpp" + +#endif // QT_NO_IDENTITYPROXYMODEL diff --git a/src/gui/itemviews/qidentityproxymodel.h b/src/gui/itemviews/qidentityproxymodel.h new file mode 100644 index 0000000..b60aa0b --- /dev/null +++ b/src/gui/itemviews/qidentityproxymodel.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, +** a KDAB Group company, info@kdab.com, +** author Stephen Kelly +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +****************************************************************************/ + + +#ifndef QIDENTITYPROXYMODEL_H +#define QIDENTITYPROXYMODEL_H + +#include + +#ifndef QT_NO_IDENTITYPROXYMODEL + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QIdentityProxyModelPrivate; + +class Q_GUI_EXPORT QIdentityProxyModel : public QAbstractProxyModel +{ + Q_OBJECT +public: + explicit QIdentityProxyModel(QObject* parent = 0); + ~QIdentityProxyModel(); + + int columnCount(const QModelIndex& parent = QModelIndex()) const; + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; + QModelIndex mapFromSource(const QModelIndex& sourceIndex) const; + QModelIndex mapToSource(const QModelIndex& proxyIndex) const; + QModelIndex parent(const QModelIndex& child) const; + int rowCount(const QModelIndex& parent = QModelIndex()) const; + bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent); + + QItemSelection mapSelectionFromSource(const QItemSelection& selection) const; + QItemSelection mapSelectionToSource(const QItemSelection& selection) const; + QModelIndexList match(const QModelIndex& start, int role, const QVariant& value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const; + void setSourceModel(QAbstractItemModel* sourceModel); + + bool insertColumns(int column, int count, const QModelIndex& parent = QModelIndex()); + bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()); + bool removeColumns(int column, int count, const QModelIndex& parent = QModelIndex()); + bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()); + +protected: + QIdentityProxyModel(QIdentityProxyModelPrivate &dd, QObject* parent); + +private: + Q_DECLARE_PRIVATE(QIdentityProxyModel) + Q_DISABLE_COPY(QIdentityProxyModel) + + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeInserted(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsInserted(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsRemoved(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)) + + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsInserted(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsRemoved(QModelIndex,int,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)) + + Q_PRIVATE_SLOT(d_func(), void _q_sourceDataChanged(QModelIndex,QModelIndex)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last)) + + Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutAboutToBeChanged()) + Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutChanged()) + Q_PRIVATE_SLOT(d_func(), void _q_sourceModelAboutToBeReset()) + Q_PRIVATE_SLOT(d_func(), void _q_sourceModelReset()) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_IDENTITYPROXYMODEL + +#endif // QIDENTITYPROXYMODEL_H + diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index eb56f56..f73607b 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -1502,7 +1502,7 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved( \l{Model Subclassing Reference}. \sa QAbstractProxyModel, QAbstractItemModel, {Model/View Programming}, - {Basic Sort/Filter Model Example}, {Custom Sort/Filter Model Example} + {Basic Sort/Filter Model Example}, {Custom Sort/Filter Model Example}, QIdentityProxyModel */ /*! diff --git a/tests/auto/gui.pro b/tests/auto/gui.pro index 186f00c..c752480 100644 --- a/tests/auto/gui.pro +++ b/tests/auto/gui.pro @@ -84,6 +84,7 @@ SUBDIRS=\ qheaderview \ qicoimageformat \ qicon \ + qidentityproxymodel \ qimageiohandler \ qimagereader \ qimagewriter \ diff --git a/tests/auto/headers/tst_headers.cpp b/tests/auto/headers/tst_headers.cpp index b5c65ef..b6135d0 100644 --- a/tests/auto/headers/tst_headers.cpp +++ b/tests/auto/headers/tst_headers.cpp @@ -243,6 +243,10 @@ void tst_Headers::licenseCheck() QCOMPARE(content.at(i++), QString("**")); if (sourceFile.endsWith("/tests/auto/modeltest/dynamictreemodel.cpp") || sourceFile.endsWith("/tests/auto/modeltest/dynamictreemodel.h") + || sourceFile.endsWith("/src/gui/itemviews/qidentityproxymodel.h") + || sourceFile.endsWith("/src/gui/itemviews/qidentityproxymodel.cpp") + || sourceFile.endsWith("/doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp") + || sourceFile.endsWith("/tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp") || sourceFile.endsWith("/src/network/kernel/qnetworkproxy_p.h")) { // These files are not copyrighted by Nokia. diff --git a/tests/auto/qidentityproxymodel/qidentityproxymodel.pro b/tests/auto/qidentityproxymodel/qidentityproxymodel.pro new file mode 100644 index 0000000..f529e20 --- /dev/null +++ b/tests/auto/qidentityproxymodel/qidentityproxymodel.pro @@ -0,0 +1,6 @@ +load(qttest_p4) + +INCLUDEPATH += $$PWD/../modeltest + +SOURCES += tst_qidentityproxymodel.cpp ../modeltest/dynamictreemodel.cpp ../modeltest/modeltest.cpp +HEADERS += ../modeltest/dynamictreemodel.h ../modeltest/modeltest.h diff --git a/tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp b/tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp new file mode 100644 index 0000000..bbcdb4c --- /dev/null +++ b/tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp @@ -0,0 +1,329 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, +** a KDAB Group company, info@kdab.com, +** author Stephen Kelly +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +****************************************************************************/ + + +#include +#include "../../shared/util.h" + +#include +#include + +#include "dynamictreemodel.h" +#include "qidentityproxymodel.h" + +//TESTED CLASS= +//TESTED_FILES= + +Q_DECLARE_METATYPE(QModelIndex) + +class tst_QIdentityProxyModel : public QObject +{ + Q_OBJECT + +public: + + tst_QIdentityProxyModel(); + virtual ~tst_QIdentityProxyModel(); + +public slots: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void insertRows(); + void removeRows(); + void moveRows(); + void reset(); + +protected: + void verifyIdentity(QAbstractItemModel *model, const QModelIndex &parent = QModelIndex()); + +private: + QStandardItemModel *m_model; + QIdentityProxyModel *m_proxy; +}; + +tst_QIdentityProxyModel::tst_QIdentityProxyModel() + : m_model(0), m_proxy(0) +{ + +} + +tst_QIdentityProxyModel::~tst_QIdentityProxyModel() +{ + +} + +void tst_QIdentityProxyModel::initTestCase() +{ + qRegisterMetaType("QModelIndex"); + + m_model = new QStandardItemModel(0, 1); + m_proxy = new QIdentityProxyModel(); +} + +void tst_QIdentityProxyModel::cleanupTestCase() +{ + delete m_proxy; + delete m_model; +} + +void tst_QIdentityProxyModel::init() +{ +} + +void tst_QIdentityProxyModel::cleanup() +{ + m_model->clear(); + m_model->insertColumns(0, 1); +} + +void tst_QIdentityProxyModel::verifyIdentity(QAbstractItemModel *model, const QModelIndex &parent) +{ + const int rows = model->rowCount(parent); + const int columns = model->columnCount(parent); + const QModelIndex proxyParent = m_proxy->mapFromSource(parent); + + QVERIFY(m_proxy->mapToSource(proxyParent) == parent); + QVERIFY(rows == m_proxy->rowCount(proxyParent)); + QVERIFY(columns == m_proxy->columnCount(proxyParent)); + + for (int row = 0; row < rows; ++row) { + for (int column = 0; column < columns; ++column) { + const QModelIndex idx = model->index(row, column, parent); + const QModelIndex proxyIdx = m_proxy->mapFromSource(idx); + QVERIFY(proxyIdx.model() == m_proxy); + QVERIFY(m_proxy->mapToSource(proxyIdx) == idx); + QVERIFY(proxyIdx.isValid()); + QVERIFY(proxyIdx.row() == row); + QVERIFY(proxyIdx.column() == column); + QVERIFY(proxyIdx.parent() == proxyParent); + QVERIFY(proxyIdx.data() == idx.data()); + QVERIFY(proxyIdx.flags() == idx.flags()); + const int childCount = m_proxy->rowCount(proxyIdx); + const bool hasChildren = m_proxy->hasChildren(proxyIdx); + QVERIFY(model->hasChildren(idx) == hasChildren); + QVERIFY((childCount > 0) == hasChildren); + + if (hasChildren) + verifyIdentity(model, idx); + } + } +} + +/* + tests +*/ + +void tst_QIdentityProxyModel::insertRows() +{ + QStandardItem *parentItem = m_model->invisibleRootItem(); + for (int i = 0; i < 4; ++i) { + QStandardItem *item = new QStandardItem(QString("item %0").arg(i)); + parentItem->appendRow(item); + parentItem = item; + } + + m_proxy->setSourceModel(m_model); + + verifyIdentity(m_model); + + QSignalSpy modelBeforeSpy(m_model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int))); + QSignalSpy modelAfterSpy(m_model, SIGNAL(rowsInserted(QModelIndex,int,int))); + QSignalSpy proxyBeforeSpy(m_proxy, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int))); + QSignalSpy proxyAfterSpy(m_proxy, SIGNAL(rowsInserted(QModelIndex,int,int))); + + QStandardItem *item = new QStandardItem(QString("new item")); + parentItem->appendRow(item); + + QVERIFY(modelBeforeSpy.size() == 1 && 1 == proxyBeforeSpy.size()); + QVERIFY(modelAfterSpy.size() == 1 && 1 == proxyAfterSpy.size()); + + QVERIFY(modelBeforeSpy.first().first().value() == m_proxy->mapToSource(proxyBeforeSpy.first().first().value())); + QVERIFY(modelBeforeSpy.first().at(1) == proxyBeforeSpy.first().at(1)); + QVERIFY(modelBeforeSpy.first().at(2) == proxyBeforeSpy.first().at(2)); + + QVERIFY(modelAfterSpy.first().first().value() == m_proxy->mapToSource(proxyAfterSpy.first().first().value())); + QVERIFY(modelAfterSpy.first().at(1) == proxyAfterSpy.first().at(1)); + QVERIFY(modelAfterSpy.first().at(2) == proxyAfterSpy.first().at(2)); + + verifyIdentity(m_model); + +} + +void tst_QIdentityProxyModel::removeRows() +{ + QStandardItem *parentItem = m_model->invisibleRootItem(); + for (int i = 0; i < 4; ++i) { + QStandardItem *item = new QStandardItem(QString("item %0").arg(i)); + parentItem->appendRow(item); + parentItem = item; + } + + m_proxy->setSourceModel(m_model); + + verifyIdentity(m_model); + + QSignalSpy modelBeforeSpy(m_model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); + QSignalSpy modelAfterSpy(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int))); + QSignalSpy proxyBeforeSpy(m_proxy, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); + QSignalSpy proxyAfterSpy(m_proxy, SIGNAL(rowsRemoved(QModelIndex,int,int))); + + const QModelIndex topLevel = m_model->index(0, 0, QModelIndex()); + const QModelIndex secondLevel = m_model->index(0, 0, topLevel); + const QModelIndex thirdLevel = m_model->index(0, 0, secondLevel); + + QVERIFY(thirdLevel.isValid()); + + m_model->removeRow(0, secondLevel); + + QVERIFY(modelBeforeSpy.size() == 1 && 1 == proxyBeforeSpy.size()); + QVERIFY(modelAfterSpy.size() == 1 && 1 == proxyAfterSpy.size()); + + QVERIFY(modelBeforeSpy.first().first().value() == m_proxy->mapToSource(proxyBeforeSpy.first().first().value())); + QVERIFY(modelBeforeSpy.first().at(1) == proxyBeforeSpy.first().at(1)); + QVERIFY(modelBeforeSpy.first().at(2) == proxyBeforeSpy.first().at(2)); + + QVERIFY(modelAfterSpy.first().first().value() == m_proxy->mapToSource(proxyAfterSpy.first().first().value())); + QVERIFY(modelAfterSpy.first().at(1) == proxyAfterSpy.first().at(1)); + QVERIFY(modelAfterSpy.first().at(2) == proxyAfterSpy.first().at(2)); + + verifyIdentity(m_model); +} + +void tst_QIdentityProxyModel::moveRows() +{ + DynamicTreeModel model; + + { + ModelInsertCommand insertCommand(&model); + insertCommand.setStartRow(0); + insertCommand.setEndRow(9); + insertCommand.doCommand(); + } + { + ModelInsertCommand insertCommand(&model); + insertCommand.setAncestorRowNumbers(QList() << 5); + insertCommand.setStartRow(0); + insertCommand.setEndRow(9); + insertCommand.doCommand(); + } + + m_proxy->setSourceModel(&model); + + verifyIdentity(&model); + + QSignalSpy modelBeforeSpy(&model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); + QSignalSpy modelAfterSpy(&model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int))); + QSignalSpy proxyBeforeSpy(m_proxy, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))); + QSignalSpy proxyAfterSpy(m_proxy, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int))); + + { + ModelMoveCommand moveCommand(&model, 0); + moveCommand.setAncestorRowNumbers(QList() << 5); + moveCommand.setStartRow(3); + moveCommand.setEndRow(4); + moveCommand.setDestRow(1); + moveCommand.doCommand(); + } + + QVERIFY(modelBeforeSpy.size() == 1 && 1 == proxyBeforeSpy.size()); + QVERIFY(modelAfterSpy.size() == 1 && 1 == proxyAfterSpy.size()); + + QVERIFY(modelBeforeSpy.first().first().value() == m_proxy->mapToSource(proxyBeforeSpy.first().first().value())); + QVERIFY(modelBeforeSpy.first().at(1) == proxyBeforeSpy.first().at(1)); + QVERIFY(modelBeforeSpy.first().at(2) == proxyBeforeSpy.first().at(2)); + QVERIFY(modelBeforeSpy.first().at(3).value() == m_proxy->mapToSource(proxyBeforeSpy.first().at(3).value())); + QVERIFY(modelBeforeSpy.first().at(4) == proxyBeforeSpy.first().at(4)); + + QVERIFY(modelAfterSpy.first().first().value() == m_proxy->mapToSource(proxyAfterSpy.first().first().value())); + QVERIFY(modelAfterSpy.first().at(1) == proxyAfterSpy.first().at(1)); + QVERIFY(modelAfterSpy.first().at(2) == proxyAfterSpy.first().at(2)); + QVERIFY(modelAfterSpy.first().at(3).value() == m_proxy->mapToSource(proxyAfterSpy.first().at(3).value())); + QVERIFY(modelAfterSpy.first().at(4) == proxyAfterSpy.first().at(4)); + + verifyIdentity(&model); + + m_proxy->setSourceModel(0); +} + +void tst_QIdentityProxyModel::reset() +{ + DynamicTreeModel model; + + { + ModelInsertCommand insertCommand(&model); + insertCommand.setStartRow(0); + insertCommand.setEndRow(9); + insertCommand.doCommand(); + } + { + ModelInsertCommand insertCommand(&model); + insertCommand.setAncestorRowNumbers(QList() << 5); + insertCommand.setStartRow(0); + insertCommand.setEndRow(9); + insertCommand.doCommand(); + } + + m_proxy->setSourceModel(&model); + + verifyIdentity(&model); + + QSignalSpy modelBeforeSpy(&model, SIGNAL(modelAboutToBeReset())); + QSignalSpy modelAfterSpy(&model, SIGNAL(modelReset())); + QSignalSpy proxyBeforeSpy(m_proxy, SIGNAL(modelAboutToBeReset())); + QSignalSpy proxyAfterSpy(m_proxy, SIGNAL(modelReset())); + + { + ModelResetCommandFixed resetCommand(&model, 0); + resetCommand.setAncestorRowNumbers(QList() << 5); + resetCommand.setStartRow(3); + resetCommand.setEndRow(4); + resetCommand.setDestRow(1); + resetCommand.doCommand(); + } + + QVERIFY(modelBeforeSpy.size() == 1 && 1 == proxyBeforeSpy.size()); + QVERIFY(modelAfterSpy.size() == 1 && 1 == proxyAfterSpy.size()); + + verifyIdentity(&model); + m_proxy->setSourceModel(0); +} + +QTEST_MAIN(tst_QIdentityProxyModel) +#include "tst_qidentityproxymodel.moc" -- cgit v0.12 From 16fe5d5b87ed1d819bf0791fabbd121481d62d22 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Wed, 13 Apr 2011 09:31:21 +0200 Subject: qdoc: Last commit before merge into master. Added a function to class Config to unload the qdocconf file. This is for the qdoc wizard. --- tools/qdoc3/config.cpp | 27 ++++++++++++++++++++++++++- tools/qdoc3/config.h | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/tools/qdoc3/config.cpp b/tools/qdoc3/config.cpp index 838f6ac..eaec327 100644 --- a/tools/qdoc3/config.cpp +++ b/tools/qdoc3/config.cpp @@ -48,7 +48,7 @@ #include #include #include - +#include #include "config.h" #include @@ -175,6 +175,7 @@ Config::Config(const QString& programName) } /*! + The destructor has nothing special to do. */ Config::~Config() { @@ -202,6 +203,30 @@ void Config::load(const QString& fileName) } /*! + Writes the qdoc configuration data to the named file. + The previous contents of the file are overwritten. + */ +void Config::unload(const QString& fileName) +{ + + QStringMultiMap::ConstIterator v = stringValueMap.begin(); + while (v != stringValueMap.end()) { + qDebug() << v.key() << " = " << v.value(); +#if 0 + if (v.key().startsWith(varDot)) { + QString subVar = v.key().mid(varDot.length()); + int dot = subVar.indexOf(QLatin1Char('.')); + if (dot != -1) + subVar.truncate(dot); + t.insert(subVar,v.value()); + } +#endif + ++v; + } + qDebug() << "fileName:" << fileName; +} + +/*! Joins all the strings in \a values into a single string with the individual \a values separated by ' '. Then it inserts the result into the string list map with \a var as the key. diff --git a/tools/qdoc3/config.h b/tools/qdoc3/config.h index 8e19ed2..94f0060 100644 --- a/tools/qdoc3/config.h +++ b/tools/qdoc3/config.h @@ -63,6 +63,7 @@ class Config ~Config(); void load(const QString& fileName); + void unload(const QString& fileName); void setStringList(const QString& var, const QStringList& values); const QString& programName() const { return prog; } -- cgit v0.12 From f16c261348193b4c03f796db4e1e3a5db09267a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Wed, 13 Apr 2011 09:47:56 +0200 Subject: Prepared for SIMD implementation of radial gradients. Made the radial gradient fetch func into a template to be able to optimize the inner loop using SIMD instructions. Reviewed-by: Benjamin Poulain --- src/gui/painting/qdrawhelper.cpp | 200 +++++---------------------------------- src/gui/painting/qdrawhelper_p.h | 151 +++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+), 177 deletions(-) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 5e75e4a..535313e 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -75,43 +75,9 @@ enum { fixed_scale = 1 << 16, half_point = 1 << 15 }; -static const int buffer_size = 2048; - -struct LinearGradientValues -{ - qreal dx; - qreal dy; - qreal l; - qreal off; -}; -struct RadialGradientValues -{ - qreal dx; - qreal dy; - qreal a; -}; - -struct Operator; -typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length); -typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length); -typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length); - - -struct Operator -{ - QPainter::CompositionMode mode; - DestFetchProc dest_fetch; - DestStoreProc dest_store; - SourceFetchProc src_fetch; - CompositionFunctionSolid funcSolid; - CompositionFunction func; - union { - LinearGradientValues linear; - RadialGradientValues radial; -// TextureValues texture; - }; -}; +// must be multiple of 4 for easier SIMD implementations +static const int buffer_size = 2048; /* Destination fetch. This is simple as we don't have to do bounds checks or @@ -1346,64 +1312,13 @@ static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { }, }; - -static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos) -{ - int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5)); - - // calculate the actual offset. - if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) { - if (data->spread == QGradient::RepeatSpread) { - ipos = ipos % GRADIENT_STOPTABLE_SIZE; - ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos; - - } else if (data->spread == QGradient::ReflectSpread) { - const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1; - ipos = ipos % limit; - ipos = ipos < 0 ? limit + ipos : ipos; - ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos; - - } else { - if (ipos < 0) ipos = 0; - else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1; - } - } - - Q_ASSERT(ipos >= 0); - Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE); - - return data->colorTable[ipos]; -} - #define FIXPT_BITS 8 #define FIXPT_SIZE (1<> FIXPT_BITS; - - // calculate the actual offset. - if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) { - if (data->spread == QGradient::RepeatSpread) { - ipos = ipos % GRADIENT_STOPTABLE_SIZE; - ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos; - - } else if (data->spread == QGradient::ReflectSpread) { - const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1; - ipos = ipos % limit; - ipos = ipos < 0 ? limit + ipos : ipos; - ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos; - - } else { - if (ipos < 0) ipos = 0; - else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1; - } - } - - Q_ASSERT(ipos >= 0); - Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE); - - return data->colorTable[ipos]; + return data->colorTable[qt_gradient_clamp(data, ipos)]; } static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data) @@ -1419,8 +1334,8 @@ static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const Q } } -static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) +static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) { const uint *b = buffer; qreal t, inc; @@ -1487,22 +1402,6 @@ static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator return b; } -static inline qreal determinant(qreal a, qreal b, qreal c) -{ - return (b * b) - (4 * a * c); -} - -// function to evaluate real roots -static inline qreal realRoots(qreal a, qreal b, qreal detSqrt) -{ - return (-b + detSqrt)/(2 * a); -} - -static inline qreal qSafeSqrt(qreal x) -{ - return x > 0 ? qSqrt(x) : 0; -} - static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data) { v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x; @@ -1510,51 +1409,14 @@ static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const Q v->a = data->gradient.radial.radius*data->gradient.radial.radius - v->dx*v->dx - v->dy*v->dy; } -static const uint * QT_FASTCALL fetchRadialGradient(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) +class RadialFetchPlain { - const uint *b = buffer; - qreal rx = data->m21 * (y + qreal(0.5)) - + data->dx + data->m11 * (x + qreal(0.5)); - qreal ry = data->m22 * (y + qreal(0.5)) - + data->dy + data->m12 * (x + qreal(0.5)); - bool affine = !data->m13 && !data->m23; - //qreal r = data->gradient.radial.radius; - - const uint *end = buffer + length; - if (affine) { - rx -= data->gradient.radial.focal.x; - ry -= data->gradient.radial.focal.y; - - qreal inv_a = 1 / qreal(2 * op->radial.a); - - const qreal delta_rx = data->m11; - const qreal delta_ry = data->m12; - - qreal b = 2*(rx * op->radial.dx + ry * op->radial.dy); - qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy); - const qreal b_delta_b = 2 * b * delta_b; - const qreal delta_b_delta_b = 2 * delta_b * delta_b; - - const qreal bb = b * b; - const qreal delta_bb = delta_b * delta_b; - - b *= inv_a; - delta_b *= inv_a; - - const qreal rxrxryry = rx * rx + ry * ry; - const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry; - const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry); - const qreal delta_rx_plus_ry = 2 * delta_rxrxryry; - - inv_a *= inv_a; - - qreal det = (bb + 4 * op->radial.a * rxrxryry) * inv_a; - qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a; - const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a; - +public: + static inline void fetch(uint *buffer, uint *end, const QSpanData *data, qreal det, qreal delta_det, + qreal delta_delta_det, qreal b, qreal delta_b) + { while (buffer < end) { - *buffer = qt_gradient_pixel(&data->gradient, qSafeSqrt(det) - b); + *buffer = qt_gradient_pixel(&data->gradient, (det > 0 ? qSqrt(det) : 0) - b); det += delta_det; delta_det += delta_delta_det; @@ -1562,35 +1424,19 @@ static const uint * QT_FASTCALL fetchRadialGradient(uint *buffer, const Operator ++buffer; } - } else { - qreal rw = data->m23 * (y + qreal(0.5)) - + data->m33 + data->m13 * (x + qreal(0.5)); - if (!rw) - rw = 1; - while (buffer < end) { - qreal gx = rx/rw - data->gradient.radial.focal.x; - qreal gy = ry/rw - data->gradient.radial.focal.y; - qreal b = 2*(gx*op->radial.dx + gy*op->radial.dy); - qreal det = determinant(op->radial.a, b , -(gx*gx + gy*gy)); - qreal s = realRoots(op->radial.a, b, qSafeSqrt(det)); - - *buffer = qt_gradient_pixel(&data->gradient, s); - - rx += data->m11; - ry += data->m12; - rw += data->m13; - if (!rw) { - rw += data->m13; - } - ++buffer; - } } +}; - return b; +const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_radial_gradient_template(buffer, op, data, y, x, length); } -static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operator *, const QSpanData *data, - int y, int x, int length) +static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain; + +static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) { const uint *b = buffer; qreal rx = data->m21 * (y + qreal(0.5)) @@ -3347,16 +3193,16 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in case QSpanData::LinearGradient: solidSource = !data->gradient.alphaColor; getLinearGradientValues(&op.linear, data); - op.src_fetch = fetchLinearGradient; + op.src_fetch = qt_fetch_linear_gradient; break; case QSpanData::RadialGradient: solidSource = !data->gradient.alphaColor; getRadialGradientValues(&op.radial, data); - op.src_fetch = fetchRadialGradient; + op.src_fetch = qt_fetch_radial_gradient; break; case QSpanData::ConicalGradient: solidSource = !data->gradient.alphaColor; - op.src_fetch = fetchConicalGradient; + op.src_fetch = qt_fetch_conical_gradient; break; case QSpanData::Texture: op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format]; diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index d4e731b..2cfcffb 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -63,6 +63,7 @@ #endif #include "private/qrasterdefs_p.h" #include +#include #ifdef Q_WS_QWS #include "QtGui/qscreen_qws.h" @@ -178,6 +179,40 @@ void qBlendTextureCallback(int count, const QSpan *spans, void *userData); typedef void (QT_FASTCALL *CompositionFunction)(uint *dest, const uint *src, int length, uint const_alpha); typedef void (QT_FASTCALL *CompositionFunctionSolid)(uint *dest, int length, uint color, uint const_alpha); +struct LinearGradientValues +{ + qreal dx; + qreal dy; + qreal l; + qreal off; +}; + +struct RadialGradientValues +{ + qreal dx; + qreal dy; + qreal a; +}; + +struct Operator; +typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length); +typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length); +typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length); + +struct Operator +{ + QPainter::CompositionMode mode; + DestFetchProc dest_fetch; + DestStoreProc dest_store; + SourceFetchProc src_fetch; + CompositionFunctionSolid funcSolid; + CompositionFunction func; + union { + LinearGradientValues linear; + RadialGradientValues radial; + }; +}; + void qInitDrawhelperAsm(); class QRasterPaintEngine; @@ -308,6 +343,122 @@ struct QSpanData void adjustSpanMethods(); }; +static inline uint qt_gradient_clamp(const QGradientData *data, int ipos) +{ + if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) { + if (data->spread == QGradient::RepeatSpread) { + ipos = ipos % GRADIENT_STOPTABLE_SIZE; + ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos; + + } else if (data->spread == QGradient::ReflectSpread) { + const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1; + ipos = ipos % limit; + ipos = ipos < 0 ? limit + ipos : ipos; + ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos; + + } else { + if (ipos < 0) + ipos = 0; + else if (ipos >= GRADIENT_STOPTABLE_SIZE) + ipos = GRADIENT_STOPTABLE_SIZE-1; + } + } + + + Q_ASSERT(ipos >= 0); + Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE); + + return ipos; +} + +static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos) +{ + int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5)); + return data->colorTable[qt_gradient_clamp(data, ipos)]; +} + +static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c) +{ + return (b * b) - (4 * a * c); +} + +// function to evaluate real roots +static inline qreal qRadialRealRoots(qreal a, qreal b, qreal detSqrt) +{ + return (-b + detSqrt)/(2 * a); +} + +template +const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + const uint *b = buffer; + qreal rx = data->m21 * (y + qreal(0.5)) + + data->dx + data->m11 * (x + qreal(0.5)); + qreal ry = data->m22 * (y + qreal(0.5)) + + data->dy + data->m12 * (x + qreal(0.5)); + bool affine = !data->m13 && !data->m23; + + uint *end = buffer + length; + if (affine) { + rx -= data->gradient.radial.focal.x; + ry -= data->gradient.radial.focal.y; + + qreal inv_a = 1 / qreal(2 * op->radial.a); + + const qreal delta_rx = data->m11; + const qreal delta_ry = data->m12; + + qreal b = 2*(rx * op->radial.dx + ry * op->radial.dy); + qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy); + const qreal b_delta_b = 2 * b * delta_b; + const qreal delta_b_delta_b = 2 * delta_b * delta_b; + + const qreal bb = b * b; + const qreal delta_bb = delta_b * delta_b; + + b *= inv_a; + delta_b *= inv_a; + + const qreal rxrxryry = rx * rx + ry * ry; + const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry; + const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry); + const qreal delta_rx_plus_ry = 2 * delta_rxrxryry; + + inv_a *= inv_a; + + qreal det = (bb + 4 * op->radial.a * rxrxryry) * inv_a; + qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a; + const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a; + + RadialFetchFunc::fetch(buffer, end, data, det, delta_det, delta_delta_det, b, delta_b); + } else { + qreal rw = data->m23 * (y + qreal(0.5)) + + data->m33 + data->m13 * (x + qreal(0.5)); + if (!rw) + rw = 1; + while (buffer < end) { + qreal gx = rx/rw - data->gradient.radial.focal.x; + qreal gy = ry/rw - data->gradient.radial.focal.y; + qreal b = 2*(gx*op->radial.dx + gy*op->radial.dy); + qreal det = qRadialDeterminant(op->radial.a, b , -(gx*gx + gy*gy)); + qreal s = qRadialRealRoots(op->radial.a, b, (det > 0 ? qSqrt(det) : 0)); + + *buffer = qt_gradient_pixel(&data->gradient, s); + + rx += data->m11; + ry += data->m12; + rw += data->m13; + if (!rw) { + rw += data->m13; + } + ++buffer; + } + } + + return b; +} + #if defined(Q_CC_RVCT) # pragma push # pragma arm -- cgit v0.12 From 44dd7ef86a3970694a4f8fd9516575c0533a336e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Sat, 18 Sep 2010 11:04:29 +0200 Subject: Improved qt_gradient_clamp for reflect spreads. Using GRADIENT_STOPTABLE_SIZE * 2 as the modulo gives more correct behaviour, and also improves performance slightly. Reviewed-by: Benjamin Poulain --- src/gui/painting/qdrawhelper_p.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 2cfcffb..6377fe1 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -349,13 +349,11 @@ static inline uint qt_gradient_clamp(const QGradientData *data, int ipos) if (data->spread == QGradient::RepeatSpread) { ipos = ipos % GRADIENT_STOPTABLE_SIZE; ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos; - } else if (data->spread == QGradient::ReflectSpread) { - const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1; + const int limit = GRADIENT_STOPTABLE_SIZE * 2; ipos = ipos % limit; ipos = ipos < 0 ? limit + ipos : ipos; - ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos; - + ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - 1 - ipos : ipos; } else { if (ipos < 0) ipos = 0; @@ -364,7 +362,6 @@ static inline uint qt_gradient_clamp(const QGradientData *data, int ipos) } } - Q_ASSERT(ipos >= 0); Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE); -- cgit v0.12 From 26bd3dccdee8c6a8f1cf9d254a2a6be7d403aa8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 17 Sep 2010 21:53:43 +0200 Subject: Optimized radial gradient fetch using SSE 2. On an i7 this improves performance by 22 % in parcycle, 107 % in default svgviewer example, and 283 % in a synthetic radial gradient benchmark. Reviewed-by: Andreas Kling --- src/gui/painting/qdrawhelper.cpp | 5 +++ src/gui/painting/qdrawhelper_p.h | 9 ++++ src/gui/painting/qdrawhelper_sse2.cpp | 84 +++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 535313e..a676fe9 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -7734,6 +7734,11 @@ void qInitDrawhelperAsm() qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2; qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2; + + extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length); + + qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2; } #ifdef QT_HAVE_SSSE3 diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 6377fe1..db5ec70 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -268,8 +268,10 @@ struct QGradientData #ifdef Q_WS_QWS #define GRADIENT_STOPTABLE_SIZE 256 +#define GRADIENT_STOPTABLE_SIZE_SHIFT 8 #else #define GRADIENT_STOPTABLE_SIZE 1024 +#define GRADIENT_STOPTABLE_SIZE_SHIFT 10 #endif uint* colorTable; //[GRADIENT_STOPTABLE_SIZE]; @@ -389,6 +391,13 @@ template const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { + // avoid division by zero + if (qFuzzyIsNull(op->radial.a)) { + extern void (*qt_memfill32)(quint32 *dest, quint32 value, int count); + qt_memfill32(buffer, data->gradient.colorTable[0], length); + return buffer; + } + const uint *b = buffer; qreal rx = data->m21 * (y + qreal(0.5)) + data->dx + data->m11 * (x + qreal(0.5)); diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index aad6bc9..eef4cda 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -491,6 +491,90 @@ void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y, } } +extern const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length); +class RadialFetchSse2 +{ +public: + static inline void fetch(uint *buffer, uint *end, const QSpanData *data, qreal det, qreal delta_det, + qreal delta_delta_det, qreal b, qreal delta_b) + { + union Vect_buffer_f { __m128 v; float f[4]; }; + union Vect_buffer_i { __m128i v; int i[4]; }; + + Vect_buffer_f det_vec; + Vect_buffer_f delta_det4_vec; + Vect_buffer_f b_vec; + + for (int i = 0; i < 4; ++i) { + det_vec.f[i] = det; + delta_det4_vec.f[i] = 4 * delta_det; + b_vec.f[i] = b; + + det += delta_det; + delta_det += delta_delta_det; + b += delta_b; + } + + const __m128 v_delta_delta_det16 = _mm_set1_ps(16 * delta_delta_det); + const __m128 v_delta_delta_det6 = _mm_set1_ps(6 * delta_delta_det); + const __m128 v_delta_b4 = _mm_set1_ps(4 * delta_b); + + const __m128 v_min = _mm_set1_ps(0.0f); + const __m128 v_max = _mm_set1_ps(GRADIENT_STOPTABLE_SIZE-1.5f); + const __m128 v_half = _mm_set1_ps(0.5f); + + const __m128 v_table_size_minus_one = _mm_set1_ps(float(GRADIENT_STOPTABLE_SIZE-1)); + + const __m128i v_repeat_mask = _mm_set1_epi32(uint(0xffffff) << GRADIENT_STOPTABLE_SIZE_SHIFT); + const __m128i v_reflect_mask = _mm_set1_epi32(uint(0xffffff) << (GRADIENT_STOPTABLE_SIZE_SHIFT+1)); + + const __m128i v_reflect_limit = _mm_set1_epi32(2 * GRADIENT_STOPTABLE_SIZE - 1); + +#define FETCH_RADIAL_LOOP_PROLOGUE \ + while (buffer < end) { \ + const __m128 v_index_local = _mm_sub_ps(_mm_sqrt_ps(_mm_max_ps(v_min, det_vec.v)), b_vec.v); \ + const __m128 v_index = _mm_add_ps(_mm_mul_ps(v_index_local, v_table_size_minus_one), v_half); \ + Vect_buffer_i index_vec; +#define FETCH_RADIAL_LOOP_CLAMP_REPEAT \ + index_vec.v = _mm_andnot_si128(v_repeat_mask, _mm_cvttps_epi32(v_index)); +#define FETCH_RADIAL_LOOP_CLAMP_REFLECT \ + const __m128i v_index_i = _mm_andnot_si128(v_reflect_mask, _mm_cvttps_epi32(v_index)); \ + const __m128i v_index_i_inv = _mm_sub_epi32(v_reflect_limit, v_index_i); \ + index_vec.v = _mm_min_epi16(v_index_i, v_index_i_inv); +#define FETCH_RADIAL_LOOP_CLAMP_PAD \ + index_vec.v = _mm_cvttps_epi32(_mm_min_ps(v_max, _mm_max_ps(v_min, v_index))); +#define FETCH_RADIAL_LOOP_EPILOGUE \ + det_vec.v = _mm_add_ps(_mm_add_ps(det_vec.v, delta_det4_vec.v), v_delta_delta_det6); \ + delta_det4_vec.v = _mm_add_ps(delta_det4_vec.v, v_delta_delta_det16); \ + b_vec.v = _mm_add_ps(b_vec.v, v_delta_b4); \ + for (int i = 0; i < 4; ++i) \ + *buffer++ = data->gradient.colorTable[index_vec.i[i]]; \ + } + + if (data->gradient.spread == QGradient::RepeatSpread) { + FETCH_RADIAL_LOOP_PROLOGUE + FETCH_RADIAL_LOOP_CLAMP_REPEAT + FETCH_RADIAL_LOOP_EPILOGUE + } else if (data->gradient.spread == QGradient::ReflectSpread) { + FETCH_RADIAL_LOOP_PROLOGUE + FETCH_RADIAL_LOOP_CLAMP_REFLECT + FETCH_RADIAL_LOOP_EPILOGUE + } else { + FETCH_RADIAL_LOOP_PROLOGUE + FETCH_RADIAL_LOOP_CLAMP_PAD + FETCH_RADIAL_LOOP_EPILOGUE + } + } +}; + +const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_radial_gradient_template(buffer, op, data, y, x, length); +} + + QT_END_NAMESPACE #endif // QT_HAVE_SSE2 -- cgit v0.12 From 5b74a70ac630073582be56f8a0539624a1080185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Wed, 13 Apr 2011 10:15:06 +0200 Subject: Improved gradient table generation performance for two-stop gradients. Two stops is a fairly common case so we gain quite a bit by special casing it. Improves performance by 10 % in parcycle benchmark, and by 90 % in a synthetic benchmark. Reviewed-by: Andreas Kling --- src/gui/painting/qdrawhelper.cpp | 5 ++ src/gui/painting/qdrawhelper_neon.cpp | 38 ++++++++++++ src/gui/painting/qdrawhelper_p.h | 73 ++++++++++++++++++++++ src/gui/painting/qdrawhelper_sse2.cpp | 100 +++++++++---------------------- src/gui/painting/qpaintengine_raster.cpp | 78 ++++++++++++++++++++++++ tests/auto/qpainter/tst_qpainter.cpp | 39 ++++++++++-- 6 files changed, 256 insertions(+), 77 deletions(-) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index a676fe9..fd26676 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -7834,6 +7834,11 @@ void qInitDrawhelperAsm() qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon; qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon; qt_memfill32 = qt_memfill32_neon; + + extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length); + + qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon; } #endif diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index debca37..7eb2f09 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -955,6 +955,44 @@ void qt_memrotate270_16_neon(const uchar *srcPixels, int w, int h, } } +class QSimdNeon +{ +public: + typedef int32x4_t Int32x4; + typedef float32x4_t Float32x4; + + union Vect_buffer_i { Int32x4 v; int i[4]; }; + union Vect_buffer_f { Float32x4 v; float f[4]; }; + + static inline Float32x4 v_dup(float x) { return vdupq_n_f32(x); } + static inline Int32x4 v_dup(int x) { return vdupq_n_s32(x); } + static inline Int32x4 v_dup(uint x) { return vdupq_n_s32(x); } + + static inline Float32x4 v_add(Float32x4 a, Float32x4 b) { return vaddq_f32(a, b); } + static inline Int32x4 v_add(Int32x4 a, Int32x4 b) { return vaddq_s32(a, b); } + + static inline Float32x4 v_max(Float32x4 a, Float32x4 b) { return vmaxq_f32(a, b); } + static inline Float32x4 v_min(Float32x4 a, Float32x4 b) { return vminq_f32(a, b); } + static inline Int32x4 v_min_16(Int32x4 a, Int32x4 b) { return vminq_s32(a, b); } + + static inline Int32x4 v_and(Int32x4 a, Int32x4 b) { return vandq_s32(a, b); } + + static inline Float32x4 v_sub(Float32x4 a, Float32x4 b) { return vsubq_f32(a, b); } + static inline Int32x4 v_sub(Int32x4 a, Int32x4 b) { return vsubq_s32(a, b); } + + static inline Float32x4 v_mul(Float32x4 a, Float32x4 b) { return vmulq_f32(a, b); } + + static inline Float32x4 v_sqrt(Float32x4 x) { Float32x4 y = vrsqrteq_f32(x); y = vmulq_f32(y, vrsqrtsq_f32(x, vmulq_f32(y, y))); return vmulq_f32(x, y); } + + static inline Int32x4 v_toInt(Float32x4 x) { return vcvtq_s32_f32(x); } +}; + +const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_radial_gradient_template >(buffer, op, data, y, x, length); +} + QT_END_NAMESPACE #endif // QT_HAVE_NEON diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index db5ec70..a92f686 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -465,6 +465,79 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O return b; } +template +class QRadialFetchSimd +{ +public: + static inline void fetch(uint *buffer, uint *end, const QSpanData *data, qreal det, qreal delta_det, + qreal delta_delta_det, qreal b, qreal delta_b) + { + typename Simd::Vect_buffer_f det_vec; + typename Simd::Vect_buffer_f delta_det4_vec; + typename Simd::Vect_buffer_f b_vec; + + for (int i = 0; i < 4; ++i) { + det_vec.f[i] = det; + delta_det4_vec.f[i] = 4 * delta_det; + b_vec.f[i] = b; + + det += delta_det; + delta_det += delta_delta_det; + b += delta_b; + } + + const typename Simd::Float32x4 v_delta_delta_det16 = Simd::v_dup(16 * delta_delta_det); + const typename Simd::Float32x4 v_delta_delta_det6 = Simd::v_dup(6 * delta_delta_det); + const typename Simd::Float32x4 v_delta_b4 = Simd::v_dup(4 * delta_b); + + const typename Simd::Float32x4 v_min = Simd::v_dup(0.0f); + const typename Simd::Float32x4 v_max = Simd::v_dup(GRADIENT_STOPTABLE_SIZE-1.5f); + const typename Simd::Float32x4 v_half = Simd::v_dup(0.5f); + + const typename Simd::Float32x4 v_table_size_minus_one = Simd::v_dup(float(GRADIENT_STOPTABLE_SIZE-1)); + + const typename Simd::Int32x4 v_repeat_mask = Simd::v_dup(~(uint(0xffffff) << GRADIENT_STOPTABLE_SIZE_SHIFT)); + const typename Simd::Int32x4 v_reflect_mask = Simd::v_dup(~(uint(0xffffff) << (GRADIENT_STOPTABLE_SIZE_SHIFT+1))); + + const typename Simd::Int32x4 v_reflect_limit = Simd::v_dup(2 * GRADIENT_STOPTABLE_SIZE - 1); + +#define FETCH_RADIAL_LOOP_PROLOGUE \ + while (buffer < end) { \ + const typename Simd::Float32x4 v_index_local = Simd::v_sub(Simd::v_sqrt(Simd::v_max(v_min, det_vec.v)), b_vec.v); \ + const typename Simd::Float32x4 v_index = Simd::v_add(Simd::v_mul(v_index_local, v_table_size_minus_one), v_half); \ + typename Simd::Vect_buffer_i index_vec; +#define FETCH_RADIAL_LOOP_CLAMP_REPEAT \ + index_vec.v = Simd::v_and(v_repeat_mask, Simd::v_toInt(v_index)); +#define FETCH_RADIAL_LOOP_CLAMP_REFLECT \ + const typename Simd::Int32x4 v_index_i = Simd::v_and(v_reflect_mask, Simd::v_toInt(v_index)); \ + const typename Simd::Int32x4 v_index_i_inv = Simd::v_sub(v_reflect_limit, v_index_i); \ + index_vec.v = Simd::v_min_16(v_index_i, v_index_i_inv); +#define FETCH_RADIAL_LOOP_CLAMP_PAD \ + index_vec.v = Simd::v_toInt(Simd::v_min(v_max, Simd::v_max(v_min, v_index))); +#define FETCH_RADIAL_LOOP_EPILOGUE \ + det_vec.v = Simd::v_add(Simd::v_add(det_vec.v, delta_det4_vec.v), v_delta_delta_det6); \ + delta_det4_vec.v = Simd::v_add(delta_det4_vec.v, v_delta_delta_det16); \ + b_vec.v = Simd::v_add(b_vec.v, v_delta_b4); \ + for (int i = 0; i < 4; ++i) \ + *buffer++ = data->gradient.colorTable[index_vec.i[i]]; \ + } + + if (data->gradient.spread == QGradient::RepeatSpread) { + FETCH_RADIAL_LOOP_PROLOGUE + FETCH_RADIAL_LOOP_CLAMP_REPEAT + FETCH_RADIAL_LOOP_EPILOGUE + } else if (data->gradient.spread == QGradient::ReflectSpread) { + FETCH_RADIAL_LOOP_PROLOGUE + FETCH_RADIAL_LOOP_CLAMP_REFLECT + FETCH_RADIAL_LOOP_EPILOGUE + } else { + FETCH_RADIAL_LOOP_PROLOGUE + FETCH_RADIAL_LOOP_CLAMP_PAD + FETCH_RADIAL_LOOP_EPILOGUE + } + } +}; + #if defined(Q_CC_RVCT) # pragma push # pragma arm diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index eef4cda..542d845 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -491,87 +491,43 @@ void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y, } } -extern const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length); -class RadialFetchSse2 +class QSimdSse2 { public: - static inline void fetch(uint *buffer, uint *end, const QSpanData *data, qreal det, qreal delta_det, - qreal delta_delta_det, qreal b, qreal delta_b) - { - union Vect_buffer_f { __m128 v; float f[4]; }; - union Vect_buffer_i { __m128i v; int i[4]; }; - - Vect_buffer_f det_vec; - Vect_buffer_f delta_det4_vec; - Vect_buffer_f b_vec; - - for (int i = 0; i < 4; ++i) { - det_vec.f[i] = det; - delta_det4_vec.f[i] = 4 * delta_det; - b_vec.f[i] = b; - - det += delta_det; - delta_det += delta_delta_det; - b += delta_b; - } + typedef __m128i Int32x4; + typedef __m128 Float32x4; - const __m128 v_delta_delta_det16 = _mm_set1_ps(16 * delta_delta_det); - const __m128 v_delta_delta_det6 = _mm_set1_ps(6 * delta_delta_det); - const __m128 v_delta_b4 = _mm_set1_ps(4 * delta_b); - - const __m128 v_min = _mm_set1_ps(0.0f); - const __m128 v_max = _mm_set1_ps(GRADIENT_STOPTABLE_SIZE-1.5f); - const __m128 v_half = _mm_set1_ps(0.5f); - - const __m128 v_table_size_minus_one = _mm_set1_ps(float(GRADIENT_STOPTABLE_SIZE-1)); - - const __m128i v_repeat_mask = _mm_set1_epi32(uint(0xffffff) << GRADIENT_STOPTABLE_SIZE_SHIFT); - const __m128i v_reflect_mask = _mm_set1_epi32(uint(0xffffff) << (GRADIENT_STOPTABLE_SIZE_SHIFT+1)); - - const __m128i v_reflect_limit = _mm_set1_epi32(2 * GRADIENT_STOPTABLE_SIZE - 1); - -#define FETCH_RADIAL_LOOP_PROLOGUE \ - while (buffer < end) { \ - const __m128 v_index_local = _mm_sub_ps(_mm_sqrt_ps(_mm_max_ps(v_min, det_vec.v)), b_vec.v); \ - const __m128 v_index = _mm_add_ps(_mm_mul_ps(v_index_local, v_table_size_minus_one), v_half); \ - Vect_buffer_i index_vec; -#define FETCH_RADIAL_LOOP_CLAMP_REPEAT \ - index_vec.v = _mm_andnot_si128(v_repeat_mask, _mm_cvttps_epi32(v_index)); -#define FETCH_RADIAL_LOOP_CLAMP_REFLECT \ - const __m128i v_index_i = _mm_andnot_si128(v_reflect_mask, _mm_cvttps_epi32(v_index)); \ - const __m128i v_index_i_inv = _mm_sub_epi32(v_reflect_limit, v_index_i); \ - index_vec.v = _mm_min_epi16(v_index_i, v_index_i_inv); -#define FETCH_RADIAL_LOOP_CLAMP_PAD \ - index_vec.v = _mm_cvttps_epi32(_mm_min_ps(v_max, _mm_max_ps(v_min, v_index))); -#define FETCH_RADIAL_LOOP_EPILOGUE \ - det_vec.v = _mm_add_ps(_mm_add_ps(det_vec.v, delta_det4_vec.v), v_delta_delta_det6); \ - delta_det4_vec.v = _mm_add_ps(delta_det4_vec.v, v_delta_delta_det16); \ - b_vec.v = _mm_add_ps(b_vec.v, v_delta_b4); \ - for (int i = 0; i < 4; ++i) \ - *buffer++ = data->gradient.colorTable[index_vec.i[i]]; \ - } + union Vect_buffer_i { Int32x4 v; int i[4]; }; + union Vect_buffer_f { Float32x4 v; float f[4]; }; - if (data->gradient.spread == QGradient::RepeatSpread) { - FETCH_RADIAL_LOOP_PROLOGUE - FETCH_RADIAL_LOOP_CLAMP_REPEAT - FETCH_RADIAL_LOOP_EPILOGUE - } else if (data->gradient.spread == QGradient::ReflectSpread) { - FETCH_RADIAL_LOOP_PROLOGUE - FETCH_RADIAL_LOOP_CLAMP_REFLECT - FETCH_RADIAL_LOOP_EPILOGUE - } else { - FETCH_RADIAL_LOOP_PROLOGUE - FETCH_RADIAL_LOOP_CLAMP_PAD - FETCH_RADIAL_LOOP_EPILOGUE - } - } + static inline Float32x4 v_dup(float x) { return _mm_set1_ps(x); } + static inline Float32x4 v_dup(double x) { return _mm_set1_ps(x); } + static inline Int32x4 v_dup(int x) { return _mm_set1_epi32(x); } + static inline Int32x4 v_dup(uint x) { return _mm_set1_epi32(x); } + + static inline Float32x4 v_add(Float32x4 a, Float32x4 b) { return _mm_add_ps(a, b); } + static inline Int32x4 v_add(Int32x4 a, Int32x4 b) { return _mm_add_epi32(a, b); } + + static inline Float32x4 v_max(Float32x4 a, Float32x4 b) { return _mm_max_ps(a, b); } + static inline Float32x4 v_min(Float32x4 a, Float32x4 b) { return _mm_min_ps(a, b); } + static inline Int32x4 v_min_16(Int32x4 a, Int32x4 b) { return _mm_min_epi16(a, b); } + + static inline Int32x4 v_and(Int32x4 a, Int32x4 b) { return _mm_and_si128(a, b); } + + static inline Float32x4 v_sub(Float32x4 a, Float32x4 b) { return _mm_sub_ps(a, b); } + static inline Int32x4 v_sub(Int32x4 a, Int32x4 b) { return _mm_sub_epi32(a, b); } + + static inline Float32x4 v_mul(Float32x4 a, Float32x4 b) { return _mm_mul_ps(a, b); } + + static inline Float32x4 v_sqrt(Float32x4 x) { return _mm_sqrt_ps(x); } + + static inline Int32x4 v_toInt(Float32x4 x) { return _mm_cvttps_epi32(x); } }; const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { - return qt_fetch_radial_gradient_template(buffer, op, data, y, x, length); + return qt_fetch_radial_gradient_template >(buffer, op, data, y, x, length); } diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 6902543..8486adb 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -5033,6 +5033,84 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); + if (stopCount == 2) { + uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity); + uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity); + + qreal first_stop = stops[0].first; + qreal second_stop = stops[1].first; + + if (second_stop < first_stop) { + qSwap(first_color, second_color); + qSwap(first_stop, second_stop); + } + + if (colorInterpolation) { + first_color = PREMUL(first_color); + second_color = PREMUL(second_color); + } + + int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1)); + int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1)); + + uint red_first = qRed(first_color) << 16; + uint green_first = qGreen(first_color) << 16; + uint blue_first = qBlue(first_color) << 16; + uint alpha_first = qAlpha(first_color) << 16; + + uint red_second = qRed(second_color) << 16; + uint green_second = qGreen(second_color) << 16; + uint blue_second = qBlue(second_color) << 16; + uint alpha_second = qAlpha(second_color) << 16; + + int i = 0; + for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) { + if (colorInterpolation) + colorTable[i] = first_color; + else + colorTable[i] = PREMUL(first_color); + } + + if (i < second_index) { + qreal reciprocal = qreal(1) / (second_index - first_index); + + int red_delta = qRound(int(red_second - red_first) * reciprocal); + int green_delta = qRound(int(green_second - green_first) * reciprocal); + int blue_delta = qRound(int(blue_second - blue_first) * reciprocal); + int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal); + + // rounding + red_first += 1 << 15; + green_first += 1 << 15; + blue_first += 1 << 15; + alpha_first += 1 << 15; + + for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) { + red_first += red_delta; + green_first += green_delta; + blue_first += blue_delta; + alpha_first += alpha_delta; + + const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000) + | ((green_first >> 8) & 0xff00) | (blue_first >> 16); + + if (colorInterpolation) + colorTable[i] = color; + else + colorTable[i] = PREMUL(color); + } + } + + for (; i < GRADIENT_STOPTABLE_SIZE; ++i) { + if (colorInterpolation) + colorTable[i] = second_color; + else + colorTable[i] = PREMUL(second_color); + } + + return; + } + uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity); if (stopCount == 1) { current_color = PREMUL(current_color); diff --git a/tests/auto/qpainter/tst_qpainter.cpp b/tests/auto/qpainter/tst_qpainter.cpp index c21514b..fa80635 100644 --- a/tests/auto/qpainter/tst_qpainter.cpp +++ b/tests/auto/qpainter/tst_qpainter.cpp @@ -77,6 +77,7 @@ # define SRCDIR "." #endif +Q_DECLARE_METATYPE(QGradientStops) Q_DECLARE_METATYPE(QLine) Q_DECLARE_METATYPE(QRect) Q_DECLARE_METATYPE(QSize) @@ -189,6 +190,7 @@ private slots: void fillRect_stretchToDeviceMode(); void monoImages(); + void linearGradientSymmetry_data(); void linearGradientSymmetry(); void gradientInterpolation(); @@ -3983,8 +3985,39 @@ static QLinearGradient inverseGradient(QLinearGradient g) return g2; } +void tst_QPainter::linearGradientSymmetry_data() +{ + QTest::addColumn("stops"); + + { + QGradientStops stops; + stops << qMakePair(qreal(0.0), QColor(Qt::blue)); + stops << qMakePair(qreal(0.2), QColor(220, 220, 220, 0)); + stops << qMakePair(qreal(0.6), QColor(Qt::red)); + stops << qMakePair(qreal(0.9), QColor(220, 220, 220, 255)); + stops << qMakePair(qreal(1.0), QColor(Qt::black)); + QTest::newRow("multiple stops") << stops; + } + + { + QGradientStops stops; + stops << qMakePair(qreal(0.0), QColor(Qt::blue)); + stops << qMakePair(qreal(1.0), QColor(Qt::black)); + QTest::newRow("two stops") << stops; + } + + { + QGradientStops stops; + stops << qMakePair(qreal(0.3), QColor(Qt::blue)); + stops << qMakePair(qreal(0.6), QColor(Qt::black)); + QTest::newRow("two stops 2") << stops; + } +} + void tst_QPainter::linearGradientSymmetry() { + QFETCH(QGradientStops, stops); + QImage a(64, 8, QImage::Format_ARGB32_Premultiplied); QImage b(64, 8, QImage::Format_ARGB32_Premultiplied); @@ -3992,11 +4025,7 @@ void tst_QPainter::linearGradientSymmetry() b.fill(0); QLinearGradient gradient(QRectF(b.rect()).topLeft(), QRectF(b.rect()).topRight()); - gradient.setColorAt(0.0, Qt::blue); - gradient.setColorAt(0.2, QColor(220, 220, 220, 0)); - gradient.setColorAt(0.6, Qt::red); - gradient.setColorAt(0.9, QColor(220, 220, 220, 255)); - gradient.setColorAt(1.0, Qt::black); + gradient.setStops(stops); QPainter pa(&a); pa.fillRect(a.rect(), gradient); -- cgit v0.12 From da55c1ea92474e989e5582b02815936bbf584405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Wed, 13 Apr 2011 10:16:43 +0200 Subject: Added support for six-parameter radial gradients. The extended radial gradients conform to the radial gradient specification in HTML 5 canvas. Task-number: QTBUG-14075 Reviewed-by: Andreas Kling --- src/gui/painting/qbrush.cpp | 191 ++++++++++++++++++--- src/gui/painting/qbrush.h | 12 +- src/gui/painting/qdrawhelper.cpp | 42 ++++- src/gui/painting/qdrawhelper_neon.cpp | 2 + src/gui/painting/qdrawhelper_p.h | 100 +++++++---- src/gui/painting/qdrawhelper_sse2.cpp | 2 + src/gui/painting/qpaintengine_mac.cpp | 3 +- src/gui/painting/qpaintengine_raster.cpp | 3 +- src/gui/painting/qpaintengineex.cpp | 46 +++++ src/gui/painting/qpainter.cpp | 14 +- src/gui/painting/qpainter.h | 1 + .../gl2paintengineex/qglengineshadermanager.cpp | 2 + .../gl2paintengineex/qglengineshadermanager_p.h | 2 + .../gl2paintengineex/qglengineshadersource_p.h | 18 +- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 8 +- src/opengl/qpaintengine_opengl.cpp | 60 ++----- src/openvg/qpaintengine_vg.cpp | 111 ++++++++++++ tests/arthur/common/paintcommands.cpp | 34 +++- tests/arthur/common/paintcommands.h | 1 + .../arthur/data/qps/radial_gradients_extended.qps | 95 ++++++++++ .../data/qps/radial_gradients_extended_qps.png | Bin 0 -> 107978 bytes 21 files changed, 617 insertions(+), 130 deletions(-) create mode 100644 tests/arthur/data/qps/radial_gradients_extended.qps create mode 100644 tests/arthur/data/qps/radial_gradients_extended_qps.png diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index bf5764a..3ff7eb8 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -840,6 +840,22 @@ const QGradient *QBrush::gradient() const return 0; } +Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush) +{ + if (brush.style() == Qt::RadialGradientPattern) { + const QGradient *g = brush.gradient(); + const QRadialGradient *rg = static_cast(g); + + if (!qFuzzyIsNull(rg->focalRadius())) + return true; + + QPointF delta = rg->focalPoint() - rg->center(); + if (delta.x() * delta.x() + delta.y() * delta.y() > rg->radius() * rg->radius()) + return true; + } + + return false; +} /*! Returns true if the brush is fully opaque otherwise false. A brush @@ -849,6 +865,7 @@ const QGradient *QBrush::gradient() const \i The alpha component of the color() is 255. \i Its texture() does not have an alpha channel and is not a QBitmap. \i The colors in the gradient() all have an alpha component that is 255. + \i It is an extended radial gradient. \endlist */ @@ -860,6 +877,9 @@ bool QBrush::isOpaque() const if (d->style == Qt::SolidPattern) return opaqueColor; + if (qt_isExtendedRadialGradient(*this)) + return false; + if (d->style == Qt::LinearGradientPattern || d->style == Qt::RadialGradientPattern || d->style == Qt::ConicalGradientPattern) { @@ -1209,8 +1229,10 @@ QDataStream &operator>>(QDataStream &s, QBrush &b) \list \o \e Linear gradients interpolate colors between start and end points. - \o \e Radial gradients interpolate colors between a focal point and end - points on a circle surrounding it. + \o \e Simple radial gradients interpolate colors between a focal point + and end points on a circle surrounding it. + \o \e Extended radial gradients interpolate colors between a center and + a focal circle. \o \e Conical gradients interpolate colors around a center point. \endlist @@ -1506,8 +1528,6 @@ void QGradient::setInterpolationMode(InterpolationMode mode) dummy = p; } -#undef Q_DUMMY_ACCESSOR - /*! \fn bool QGradient::operator!=(const QGradient &gradient) const \since 4.2 @@ -1541,7 +1561,7 @@ bool QGradient::operator==(const QGradient &gradient) const || m_data.radial.cy != gradient.m_data.radial.cy || m_data.radial.fx != gradient.m_data.radial.fx || m_data.radial.fy != gradient.m_data.radial.fy - || m_data.radial.radius != gradient.m_data.radial.radius) + || m_data.radial.cradius != gradient.m_data.radial.cradius) return false; } else { // m_type == ConicalGradient if (m_data.conical.cx != gradient.m_data.conical.cx @@ -1747,10 +1767,17 @@ void QLinearGradient::setFinalStop(const QPointF &stop) \brief The QRadialGradient class is used in combination with QBrush to specify a radial gradient brush. - Radial gradients interpolate colors between a focal point and end - points on a circle surrounding it. Outside the end points the - gradient is either padded, reflected or repeated depending on the - currently set \l {QGradient::Spread}{spread} method: + Qt supports both simple and extended radial gradients. + + Simple radial gradients interpolate colors between a focal point and end + points on a circle surrounding it. Extended radial gradients interpolate + colors between a focal circle and a center circle. Points outside the cone + defined by the two circles will be transparent. For simple radial gradients + the focal point is adjusted to lie inside the center circle, whereas the + focal point can have any position in an extended radial gradient. + + Outside the end points the gradient is either padded, reflected or repeated + depending on the currently set \l {QGradient::Spread}{spread} method: \table \row @@ -1795,9 +1822,14 @@ static QPointF qt_radial_gradient_adapt_focal_point(const QPointF ¢er, } /*! - Constructs a radial gradient with the given \a center, \a + Constructs a simple radial gradient with the given \a center, \a radius and \a focalPoint. + \note If the given focal point is outside the circle defined by the + center (\a cx, \a cy) and the \a radius it will be re-adjusted to + the intersection between the line from the center to the focal point + and the circle. + \sa QGradient::setColorAt(), QGradient::setStops() */ @@ -1807,7 +1839,7 @@ QRadialGradient::QRadialGradient(const QPointF ¢er, qreal radius, const QPoi m_spread = PadSpread; m_data.radial.cx = center.x(); m_data.radial.cy = center.y(); - m_data.radial.radius = radius; + m_data.radial.cradius = radius; QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(center, radius, focalPoint); m_data.radial.fx = adapted_focal.x(); @@ -1815,7 +1847,7 @@ QRadialGradient::QRadialGradient(const QPointF ¢er, qreal radius, const QPoi } /*! - Constructs a radial gradient with the given \a center, \a + Constructs a simple radial gradient with the given \a center, \a radius and the focal point in the circle center. \sa QGradient::setColorAt(), QGradient::setStops() @@ -1826,16 +1858,21 @@ QRadialGradient::QRadialGradient(const QPointF ¢er, qreal radius) m_spread = PadSpread; m_data.radial.cx = center.x(); m_data.radial.cy = center.y(); - m_data.radial.radius = radius; + m_data.radial.cradius = radius; m_data.radial.fx = center.x(); m_data.radial.fy = center.y(); } /*! - Constructs a radial gradient with the given center (\a cx, \a cy), + Constructs a simple radial gradient with the given center (\a cx, \a cy), \a radius and focal point (\a fx, \a fy). + \note If the given focal point is outside the circle defined by the + center (\a cx, \a cy) and the \a radius it will be re-adjusted to + the intersection between the line from the center to the focal point + and the circle. + \sa QGradient::setColorAt(), QGradient::setStops() */ @@ -1845,7 +1882,7 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qre m_spread = PadSpread; m_data.radial.cx = cx; m_data.radial.cy = cy; - m_data.radial.radius = radius; + m_data.radial.cradius = radius; QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(QPointF(cx, cy), radius, @@ -1856,7 +1893,7 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qre } /*! - Constructs a radial gradient with the center at (\a cx, \a cy) and the + Constructs a simple radial gradient with the center at (\a cx, \a cy) and the specified \a radius. The focal point lies at the center of the circle. \sa QGradient::setColorAt(), QGradient::setStops() @@ -1867,14 +1904,14 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius) m_spread = PadSpread; m_data.radial.cx = cx; m_data.radial.cy = cy; - m_data.radial.radius = radius; + m_data.radial.cradius = radius; m_data.radial.fx = cx; m_data.radial.fy = cy; } /*! - Constructs a radial gradient with the center and focal point at + Constructs a simple radial gradient with the center and focal point at (0, 0) with a radius of 1. */ QRadialGradient::QRadialGradient() @@ -1883,11 +1920,51 @@ QRadialGradient::QRadialGradient() m_spread = PadSpread; m_data.radial.cx = 0; m_data.radial.cy = 0; - m_data.radial.radius = 1; + m_data.radial.cradius = 1; m_data.radial.fx = 0; m_data.radial.fy = 0; } +/*! + \since 4.8 + + Constructs an extended radial gradient with the given \a center, \a + centerRadius, \a focalPoint, and \a focalRadius. +*/ +QRadialGradient::QRadialGradient(const QPointF ¢er, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius) +{ + m_type = RadialGradient; + m_spread = PadSpread; + m_data.radial.cx = center.x(); + m_data.radial.cy = center.y(); + m_data.radial.cradius = centerRadius; + + m_data.radial.fx = focalPoint.x(); + m_data.radial.fy = focalPoint.y(); + setFocalRadius(focalRadius); +} + +/*! + \since 4.8 + + Constructs an extended radial gradient with the given \a center, \a + centerRadius, \a focalPoint, and \a focalRadius. + Constructs a radial gradient with the given center (\a cx, \a cy), + center radius \a centerRadius, focal point (\a fx, \a fy), and + focal radius \a focalRadius. +*/ +QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius) +{ + m_type = RadialGradient; + m_spread = PadSpread; + m_data.radial.cx = cx; + m_data.radial.cy = cy; + m_data.radial.cradius = centerRadius; + + m_data.radial.fx = fx; + m_data.radial.fy = fy; + setFocalRadius(focalRadius); +} /*! Returns the center of this radial gradient in logical coordinates. @@ -1932,13 +2009,15 @@ void QRadialGradient::setCenter(const QPointF ¢er) /*! Returns the radius of this radial gradient in logical coordinates. + Equivalent to centerRadius() + \sa QGradient::stops() */ qreal QRadialGradient::radius() const { Q_ASSERT(m_type == RadialGradient); - return m_data.radial.radius; + return m_data.radial.cradius; } @@ -1947,13 +2026,81 @@ qreal QRadialGradient::radius() const Sets the radius of this radial gradient in logical coordinates to \a radius + + Equivalent to setCenterRadius() */ void QRadialGradient::setRadius(qreal radius) { Q_ASSERT(m_type == RadialGradient); - m_data.radial.radius = radius; + m_data.radial.cradius = radius; +} + +/*! + \since 4.8 + + Returns the center radius of this radial gradient in logical + coordinates. + + \sa QGradient::stops() +*/ +qreal QRadialGradient::centerRadius() const +{ + Q_ASSERT(m_type == RadialGradient); + return m_data.radial.cradius; +} + +/* + \since 4.8 + + Sets the center radius of this radial gradient in logical coordinates + to \a radius +*/ +void QRadialGradient::setCenterRadius(qreal radius) +{ + Q_ASSERT(m_type == RadialGradient); + m_data.radial.cradius = radius; +} + +/*! + \since 4.8 + + Returns the focal radius of this radial gradient in logical + coordinates. + + \sa QGradient::stops() +*/ +qreal QRadialGradient::focalRadius() const +{ + Q_ASSERT(m_type == RadialGradient); + Q_DUMMY_ACCESSOR + + // mask away low three bits + union { float f; quint32 i; } u; + u.i = i & ~0x07; + return u.f; } +/* + \since 4.8 + + Sets the focal radius of this radial gradient in logical coordinates + to \a radius +*/ +void QRadialGradient::setFocalRadius(qreal radius) +{ + Q_ASSERT(m_type == RadialGradient); + Q_DUMMY_ACCESSOR + + // Since there's no QGradientData, we only have the dummy void * to + // store additional data in. The three lowest bits are already + // taken, thus we cut the three lowest bits from the significand + // and store the radius as a float. + union { float f; quint32 i; } u; + u.f = float(radius); + // add 0x04 to round up when we drop the three lowest bits + i |= (u.i + 0x04) & ~0x07; + dummy = p; +} /*! Returns the focal point of this radial gradient in logical @@ -2193,4 +2340,6 @@ void QConicalGradient::setAngle(qreal angle) \sa setTransform() */ +#undef Q_DUMMY_ACCESSOR + QT_END_NAMESPACE diff --git a/src/gui/painting/qbrush.h b/src/gui/painting/qbrush.h index 8b31319..d914c8c 100644 --- a/src/gui/painting/qbrush.h +++ b/src/gui/painting/qbrush.h @@ -255,6 +255,7 @@ private: friend class QLinearGradient; friend class QRadialGradient; friend class QConicalGradient; + friend class QBrush; Type m_type; Spread m_spread; @@ -264,7 +265,7 @@ private: qreal x1, y1, x2, y2; } linear; struct { - qreal cx, cy, fx, fy, radius; + qreal cx, cy, fx, fy, cradius; } radial; struct { qreal cx, cy, angle; @@ -303,6 +304,9 @@ public: QRadialGradient(const QPointF ¢er, qreal radius); QRadialGradient(qreal cx, qreal cy, qreal radius); + QRadialGradient(const QPointF ¢er, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius); + QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius); + QPointF center() const; void setCenter(const QPointF ¢er); inline void setCenter(qreal x, qreal y) { setCenter(QPointF(x, y)); } @@ -313,6 +317,12 @@ public: qreal radius() const; void setRadius(qreal radius); + + qreal centerRadius() const; + void setCenterRadius(qreal radius); + + qreal focalRadius() const; + void setFocalRadius(qreal radius); }; diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index fd26676..ae9993e 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -1406,23 +1406,47 @@ static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const Q { v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x; v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y; - v->a = data->gradient.radial.radius*data->gradient.radial.radius - v->dx*v->dx - v->dy*v->dy; + + v->dr = data->gradient.radial.center.radius - data->gradient.radial.focal.radius; + v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius; + + v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy; + v->inv2a = 1 / (2 * v->a); + + v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0; } class RadialFetchPlain { public: - static inline void fetch(uint *buffer, uint *end, const QSpanData *data, qreal det, qreal delta_det, - qreal delta_delta_det, qreal b, qreal delta_b) + static inline void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det, + qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) { - while (buffer < end) { - *buffer = qt_gradient_pixel(&data->gradient, (det > 0 ? qSqrt(det) : 0) - b); + if (op->radial.extended) { + while (buffer < end) { + quint32 result = 0; + if (det >= 0) { + qreal w = qSqrt(det) - b; + if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0) + result = qt_gradient_pixel(&data->gradient, w); + } - det += delta_det; - delta_det += delta_delta_det; - b += delta_b; + *buffer = result; - ++buffer; + det += delta_det; + delta_det += delta_delta_det; + b += delta_b; + + ++buffer; + } + } else { + while (buffer < end) { + *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b); + + det += delta_det; + delta_det += delta_delta_det; + b += delta_b; + } } } }; diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 7eb2f09..e673dd9 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -985,6 +985,8 @@ public: static inline Float32x4 v_sqrt(Float32x4 x) { Float32x4 y = vrsqrteq_f32(x); y = vmulq_f32(y, vrsqrtsq_f32(x, vmulq_f32(y, y))); return vmulq_f32(x, y); } static inline Int32x4 v_toInt(Float32x4 x) { return vcvtq_s32_f32(x); } + + static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return vcge_f32(a, b); } }; const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data, diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index a92f686..e93d736 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -191,7 +191,11 @@ struct RadialGradientValues { qreal dx; qreal dy; + qreal dr; + qreal sqrfr; qreal a; + qreal inv2a; + bool extended; }; struct Operator; @@ -239,12 +243,13 @@ struct QRadialGradientData struct { qreal x; qreal y; + qreal radius; } center; struct { qreal x; qreal y; + qreal radius; } focal; - qreal radius; }; struct QConicalGradientData @@ -381,12 +386,6 @@ static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c) return (b * b) - (4 * a * c); } -// function to evaluate real roots -static inline qreal qRadialRealRoots(qreal a, qreal b, qreal detSqrt) -{ - return (-b + detSqrt)/(2 * a); -} - template const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) @@ -394,7 +393,7 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O // avoid division by zero if (qFuzzyIsNull(op->radial.a)) { extern void (*qt_memfill32)(quint32 *dest, quint32 value, int count); - qt_memfill32(buffer, data->gradient.colorTable[0], length); + qt_memfill32(buffer, 0, length); return buffer; } @@ -415,7 +414,7 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O const qreal delta_rx = data->m11; const qreal delta_ry = data->m12; - qreal b = 2*(rx * op->radial.dx + ry * op->radial.dy); + qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + rx * op->radial.dx + ry * op->radial.dy); qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy); const qreal b_delta_b = 2 * b * delta_b; const qreal delta_b_delta_b = 2 * delta_b * delta_b; @@ -433,31 +432,45 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O inv_a *= inv_a; - qreal det = (bb + 4 * op->radial.a * rxrxryry) * inv_a; + qreal det = (bb - 4 * op->radial.a * (op->radial.sqrfr - rxrxryry)) * inv_a; qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a; const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a; - RadialFetchFunc::fetch(buffer, end, data, det, delta_det, delta_delta_det, b, delta_b); + RadialFetchFunc::fetch(buffer, end, op, data, det, delta_det, delta_delta_det, b, delta_b); } else { qreal rw = data->m23 * (y + qreal(0.5)) + data->m33 + data->m13 * (x + qreal(0.5)); - if (!rw) - rw = 1; + while (buffer < end) { - qreal gx = rx/rw - data->gradient.radial.focal.x; - qreal gy = ry/rw - data->gradient.radial.focal.y; - qreal b = 2*(gx*op->radial.dx + gy*op->radial.dy); - qreal det = qRadialDeterminant(op->radial.a, b , -(gx*gx + gy*gy)); - qreal s = qRadialRealRoots(op->radial.a, b, (det > 0 ? qSqrt(det) : 0)); + if (rw == 0) { + *buffer = 0; + } else { + qreal invRw = 1 / rw; + qreal gx = rx * invRw - data->gradient.radial.focal.x; + qreal gy = ry * invRw - data->gradient.radial.focal.y; + qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + gx*op->radial.dx + gy*op->radial.dy); + qreal det = qRadialDeterminant(op->radial.a, b, op->radial.sqrfr - (gx*gx + gy*gy)); + + quint32 result = 0; + if (det >= 0) { + qreal detSqrt = qSqrt(det); + + qreal s0 = (-b - detSqrt) * op->radial.inv2a; + qreal s1 = (-b + detSqrt) * op->radial.inv2a; + + qreal s = qMax(s0, s1); - *buffer = qt_gradient_pixel(&data->gradient, s); + if (data->gradient.radial.focal.radius + op->radial.dr * s >= 0) + result = qt_gradient_pixel(&data->gradient, s); + } + + *buffer = result; + } rx += data->m11; ry += data->m12; rw += data->m13; - if (!rw) { - rw += data->m13; - } + ++buffer; } } @@ -469,8 +482,8 @@ template class QRadialFetchSimd { public: - static inline void fetch(uint *buffer, uint *end, const QSpanData *data, qreal det, qreal delta_det, - qreal delta_delta_det, qreal b, qreal delta_b) + static void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det, + qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) { typename Simd::Vect_buffer_f det_vec; typename Simd::Vect_buffer_f delta_det4_vec; @@ -490,6 +503,9 @@ public: const typename Simd::Float32x4 v_delta_delta_det6 = Simd::v_dup(6 * delta_delta_det); const typename Simd::Float32x4 v_delta_b4 = Simd::v_dup(4 * delta_b); + const typename Simd::Float32x4 v_r0 = Simd::v_dup(data->gradient.radial.focal.radius); + const typename Simd::Float32x4 v_dr = Simd::v_dup(op->radial.dr); + const typename Simd::Float32x4 v_min = Simd::v_dup(0.0f); const typename Simd::Float32x4 v_max = Simd::v_dup(GRADIENT_STOPTABLE_SIZE-1.5f); const typename Simd::Float32x4 v_half = Simd::v_dup(0.5f); @@ -501,10 +517,15 @@ public: const typename Simd::Int32x4 v_reflect_limit = Simd::v_dup(2 * GRADIENT_STOPTABLE_SIZE - 1); + const int extended_mask = op->radial.extended ? 0x0 : ~0x0; + #define FETCH_RADIAL_LOOP_PROLOGUE \ while (buffer < end) { \ + typename Simd::Vect_buffer_i v_buffer_mask; \ + v_buffer_mask.v = Simd::v_greaterOrEqual(det_vec.v, v_min); \ const typename Simd::Float32x4 v_index_local = Simd::v_sub(Simd::v_sqrt(Simd::v_max(v_min, det_vec.v)), b_vec.v); \ const typename Simd::Float32x4 v_index = Simd::v_add(Simd::v_mul(v_index_local, v_table_size_minus_one), v_half); \ + v_buffer_mask.v = Simd::v_and(v_buffer_mask.v, Simd::v_greaterOrEqual(Simd::v_add(v_r0, Simd::v_mul(v_dr, v_index_local)), v_min)); \ typename Simd::Vect_buffer_i index_vec; #define FETCH_RADIAL_LOOP_CLAMP_REPEAT \ index_vec.v = Simd::v_and(v_repeat_mask, Simd::v_toInt(v_index)); @@ -519,21 +540,26 @@ public: delta_det4_vec.v = Simd::v_add(delta_det4_vec.v, v_delta_delta_det16); \ b_vec.v = Simd::v_add(b_vec.v, v_delta_b4); \ for (int i = 0; i < 4; ++i) \ - *buffer++ = data->gradient.colorTable[index_vec.i[i]]; \ + *buffer++ = (extended_mask | v_buffer_mask.i[i]) & data->gradient.colorTable[index_vec.i[i]]; \ } - if (data->gradient.spread == QGradient::RepeatSpread) { - FETCH_RADIAL_LOOP_PROLOGUE - FETCH_RADIAL_LOOP_CLAMP_REPEAT - FETCH_RADIAL_LOOP_EPILOGUE - } else if (data->gradient.spread == QGradient::ReflectSpread) { - FETCH_RADIAL_LOOP_PROLOGUE - FETCH_RADIAL_LOOP_CLAMP_REFLECT - FETCH_RADIAL_LOOP_EPILOGUE - } else { - FETCH_RADIAL_LOOP_PROLOGUE - FETCH_RADIAL_LOOP_CLAMP_PAD - FETCH_RADIAL_LOOP_EPILOGUE +#define FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP) \ + FETCH_RADIAL_LOOP_PROLOGUE \ + FETCH_RADIAL_LOOP_CLAMP \ + FETCH_RADIAL_LOOP_EPILOGUE + + switch (data->gradient.spread) { + case QGradient::RepeatSpread: + FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_REPEAT) + break; + case QGradient::ReflectSpread: + FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_REFLECT) + break; + case QGradient::PadSpread: + FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_PAD) + break; + default: + Q_ASSERT(false); } } }; diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index 542d845..fdab95f 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -522,6 +522,8 @@ public: static inline Float32x4 v_sqrt(Float32x4 x) { return _mm_sqrt_ps(x); } static inline Int32x4 v_toInt(Float32x4 x) { return _mm_cvttps_epi32(x); } + + static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return (__m128i)_mm_cmpgt_ps(a, b); } }; const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, diff --git a/src/gui/painting/qpaintengine_mac.cpp b/src/gui/painting/qpaintengine_mac.cpp index 8aab7c7..cc75b86 100644 --- a/src/gui/painting/qpaintengine_mac.cpp +++ b/src/gui/painting/qpaintengine_mac.cpp @@ -1544,8 +1544,9 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset) QPointF center(radialGrad->center()); QPointF focal(radialGrad->focalPoint()); qreal radius = radialGrad->radius(); + qreal focalRadius = radialGrad->focalRadius(); shading = CGShadingCreateRadial(colorspace, CGPointMake(focal.x(), focal.y()), - 0.0, CGPointMake(center.x(), center.y()), radius, fill_func, false, true); + focalRadius, CGPointMake(center.x(), center.y()), radius, fill_func, false, true); } CGFunctionRelease(fill_func); diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 8486adb..2119e30 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -5282,10 +5282,11 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode QPointF center = g->center(); radialData.center.x = center.x(); radialData.center.y = center.y(); + radialData.center.radius = g->centerRadius(); QPointF focal = g->focalPoint(); radialData.focal.x = focal.x(); radialData.focal.y = focal.y(); - radialData.radius = g->radius(); + radialData.focal.radius = g->focalRadius(); } break; diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 509fb77..7f601eb 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -1012,4 +1012,50 @@ void QPaintEngineEx::updateState(const QPaintEngineState &) // do nothing... } +Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path) +{ + const qreal *points = path.points(); + const QPainterPath::ElementType *types = path.elements(); + + QPainterPath p; + if (types) { + int id = 0; + for (int i=0; isave(); state->matrix = QTransform(); - state->dirtyFlags |= QPaintEngine::DirtyTransform; - updateState(state); + if (extended) { + extended->transformChanged(); + } else { + state->dirtyFlags |= QPaintEngine::DirtyTransform; + updateState(state); + } engine->drawImage(absPathRect, image, QRectF(0, 0, absPathRect.width(), absPathRect.height()), @@ -686,11 +690,14 @@ void QPainterPrivate::updateInvMatrix() invMatrix = state->matrix.inverted(); } +extern bool qt_isExtendedRadialGradient(const QBrush &brush); + void QPainterPrivate::updateEmulationSpecifier(QPainterState *s) { bool alpha = false; bool linearGradient = false; bool radialGradient = false; + bool extendedRadialGradient = false; bool conicalGradient = false; bool patternBrush = false; bool xform = false; @@ -722,6 +729,7 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s) (brushStyle == Qt::LinearGradientPattern)); radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) || (brushStyle == Qt::RadialGradientPattern)); + extendedRadialGradient = radialGradient && (qt_isExtendedRadialGradient(penBrush) || qt_isExtendedRadialGradient(s->brush)); conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) || (brushStyle == Qt::ConicalGradientPattern)); patternBrush = (((penBrushStyle > Qt::SolidPattern @@ -805,7 +813,7 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s) s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill; // Radial gradient emulation - if (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill)) + if (extendedRadialGradient || (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill))) s->emulationSpecifier |= QPaintEngine::RadialGradientFill; else s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill; diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index ae2fdf2..604225e 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -551,6 +551,7 @@ private: friend class QPaintEngine; friend class QPaintEngineExPrivate; friend class QOpenGLPaintEngine; + friend class QVGPaintEngine; friend class QX11PaintEngine; friend class QX11PaintEnginePrivate; friend class QWin32PaintEngine; diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 8068aa8..207ab3d 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -495,6 +495,8 @@ GLuint QGLEngineShaderManager::getUniformLocation(Uniform id) "fmp", "fmp2_m_radius2", "inverse_2_fmp2_m_radius2", + "sqrfr", + "bradius", "invertedTextureSize", "brushTransform", "brushTexture", diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h index 7cc9dc3..bf2fe42 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h @@ -442,6 +442,8 @@ public: Fmp, Fmp2MRadius2, Inverse2Fmp2MRadius2, + SqrFr, + BRadius, InvertedTextureSize, BrushTransform, BrushTexture, diff --git a/src/opengl/gl2paintengineex/qglengineshadersource_p.h b/src/opengl/gl2paintengineex/qglengineshadersource_p.h index fc8b9ef..9362c58 100644 --- a/src/opengl/gl2paintengineex/qglengineshadersource_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h @@ -241,6 +241,7 @@ static const char* const qglslPositionWithRadialGradientBrushVertexShader = "\n\ uniform mediump vec2 halfViewportSize; \n\ uniform highp mat3 brushTransform; \n\ uniform highp vec2 fmp; \n\ + uniform highp vec3 bradius; \n\ varying highp float b; \n\ varying highp vec2 A; \n\ void setPosition(void) \n\ @@ -253,7 +254,7 @@ static const char* const qglslPositionWithRadialGradientBrushVertexShader = "\n\ mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ A = hTexCoords.xy * invertedHTexCoordsZ; \n\ - b = 2.0 * dot(A, fmp); \n\ + b = bradius.x + 2.0 * dot(A, fmp); \n\ }\n"; static const char* const qglslAffinePositionWithRadialGradientBrushVertexShader @@ -263,13 +264,22 @@ static const char* const qglslRadialGradientBrushSrcFragmentShader = "\n\ uniform sampler2D brushTexture; \n\ uniform highp float fmp2_m_radius2; \n\ uniform highp float inverse_2_fmp2_m_radius2; \n\ + uniform highp float sqrfr; \n\ varying highp float b; \n\ varying highp vec2 A; \n\ + uniform highp vec3 bradius; \n\ lowp vec4 srcPixel() \n\ { \n\ - highp float c = -dot(A, A); \n\ - highp vec2 val = vec2((-b + sqrt(b*b - 4.0*fmp2_m_radius2*c)) * inverse_2_fmp2_m_radius2, 0.5); \n\ - return texture2D(brushTexture, val); \n\ + highp float c = sqrfr-dot(A, A); \n\ + highp float det = b*b - 4.0*fmp2_m_radius2*c; \n\ + lowp vec4 result = vec4(0.0); \n\ + if (det >= 0.0) { \n\ + highp float detSqrt = sqrt(det); \n\ + highp float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); \n\ + if (bradius.y + w * bradius.z >= 0.0) \n\ + result = texture2D(brushTexture, vec2(w, 0.5)); \n\ + } \n\ + return result; \n\ }\n"; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 18c684f..a2707e0 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -301,7 +301,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() const QRadialGradient *g = static_cast(currentBrush.gradient()); QPointF realCenter = g->center(); QPointF realFocal = g->focalPoint(); - qreal realRadius = g->radius(); + qreal realRadius = g->centerRadius() - g->focalRadius(); translationPoint = realFocal; QPointF fmp = realCenter - realFocal; @@ -311,6 +311,12 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Fmp2MRadius2), fmp2_m_radius2); shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Inverse2Fmp2MRadius2), GLfloat(1.0 / (2.0*fmp2_m_radius2))); + shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::SqrFr), + GLfloat(g->focalRadius() * g->focalRadius())); + shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BRadius), + GLfloat(2 * (g->centerRadius() - g->focalRadius()) * g->focalRadius()), + g->focalRadius(), + g->centerRadius() - g->focalRadius()); QVector2D halfViewportSize(width*0.5, height*0.5); shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index 2c01ac4..efa050d 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -2119,6 +2119,7 @@ void QOpenGLPaintEnginePrivate::fillPath(const QPainterPath &path) updateGLMatrix(); } +extern bool qt_isExtendedRadialGradient(const QBrush &brush); static inline bool needsEmulation(Qt::BrushStyle style) { @@ -2129,9 +2130,11 @@ static inline bool needsEmulation(Qt::BrushStyle style) void QOpenGLPaintEnginePrivate::updateUseEmulation() { - use_emulation = !use_fragment_programs - && ((has_pen && needsEmulation(pen_brush_style)) - || (has_brush && needsEmulation(brush_style))); + use_emulation = (!use_fragment_programs + && ((has_pen && needsEmulation(pen_brush_style)) + || (has_brush && needsEmulation(brush_style)))) + || (has_pen && qt_isExtendedRadialGradient(cpen.brush())) + || (has_brush && qt_isExtendedRadialGradient(cbrush)); } void QOpenGLPaintEngine::updatePen(const QPen &pen) @@ -5442,50 +5445,7 @@ void QOpenGLPaintEngine::transformChanged() updateMatrix(state()->matrix); } -static QPainterPath painterPathFromVectorPath(const QVectorPath &path) -{ - const qreal *points = path.points(); - const QPainterPath::ElementType *types = path.elements(); - - QPainterPath p; - if (types) { - int id = 0; - for (int i=0; iuse_fragment_programs && needsEmulation(brush.style())) { + if ((!d->use_fragment_programs && needsEmulation(brush.style())) || qt_isExtendedRadialGradient(brush)) { QPainter *p = painter(); QBrush oldBrush = p->brush(); p->setBrush(brush); - qt_draw_helper(p->d_ptr.data(), painterPathFromVectorPath(path), QPainterPrivate::FillDraw); + qt_draw_helper(p->d_ptr.data(), qt_painterPathFromVectorPath(path), QPainterPrivate::FillDraw); p->setBrush(oldBrush); return; } @@ -5515,7 +5475,7 @@ void QOpenGLPaintEngine::fill(const QVectorPath &path, const QBrush &brush) drawRects(&r, 1); updatePen(old_pen); } else { - d->fillPath(painterPathFromVectorPath(path)); + d->fillPath(qt_painterPathFromVectorPath(path)); } updateBrush(old_brush, state()->brushOrigin); diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index 3c2b5fd..7c9d102 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -173,6 +173,9 @@ public: bool forcePenChange; // Force a pen change, even if the same. bool forceBrushChange; // Force a brush change, even if the same. + bool hasExtendedRadialGradientPen; // Current pen's brush is extended radial gradient. + bool hasExtendedRadialGradientBrush; // Current brush is extended radial gradient. + VGPaintType penType; // Type of the last pen that was set. VGPaintType brushType; // Type of the last brush that was set. @@ -275,6 +278,27 @@ public: } } + inline bool needsEmulation(const QBrush &brush) const + { + extern bool qt_isExtendedRadialGradient(const QBrush &brush); + return qt_isExtendedRadialGradient(brush); + } + + inline bool needsEmulation() const + { + return hasExtendedRadialGradientPen || hasExtendedRadialGradientBrush; + } + + inline bool needsPenEmulation() const + { + return hasExtendedRadialGradientPen; + } + + inline bool needsBrushEmulation() const + { + return hasExtendedRadialGradientBrush; + } + // Set various modes, but only if different. inline void setImageMode(VGImageMode mode); inline void setRenderingQuality(VGRenderingQuality mode); @@ -355,6 +379,10 @@ void QVGPaintEnginePrivate::init() forcePenChange = true; forceBrushChange = true; + + hasExtendedRadialGradientPen = false; + hasExtendedRadialGradientBrush = false; + penType = (VGPaintType)0; brushType = (VGPaintType)0; @@ -1534,6 +1562,10 @@ bool QVGPaintEngine::end() void QVGPaintEngine::draw(const QVectorPath &path) { Q_D(QVGPaintEngine); + if (d->needsEmulation()) { + QPaintEngineEx::draw(path); + return; + } QVGPainterState *s = state(); VGPath vgpath = d->vectorPathToVGPath(path); if (!path.hasWindingFill()) @@ -1543,9 +1575,19 @@ void QVGPaintEngine::draw(const QVectorPath &path) vgDestroyPath(vgpath); } +extern QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path); + void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush) { Q_D(QVGPaintEngine); + if (d->needsEmulation(brush)) { + QPainter *p = painter(); + QBrush oldBrush = p->brush(); + p->setBrush(brush); + qt_draw_helper(p->d_ptr.data(), qt_painterPathFromVectorPath(path), QPainterPrivate::FillDraw); + p->setBrush(oldBrush); + return; + } VGPath vgpath = d->vectorPathToVGPath(path); if (!path.hasWindingFill()) d->fill(vgpath, brush, VG_EVEN_ODD); @@ -1557,6 +1599,10 @@ void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush) void QVGPaintEngine::stroke(const QVectorPath &path, const QPen &pen) { Q_D(QVGPaintEngine); + if (d->needsEmulation(pen.brush())) { + QPaintEngineEx::stroke(path, pen); + return; + } VGPath vgpath = d->vectorPathToVGPath(path); d->stroke(vgpath, pen); vgDestroyPath(vgpath); @@ -2360,12 +2406,17 @@ void QVGPaintEngine::penChanged() { Q_D(QVGPaintEngine); d->dirty |= QPaintEngine::DirtyPen; + + d->hasExtendedRadialGradientPen = + state()->pen.style() != Qt::NoPen && d->needsEmulation(state()->pen.brush()); } void QVGPaintEngine::brushChanged() { Q_D(QVGPaintEngine); d->dirty |= QPaintEngine::DirtyBrush; + + d->hasExtendedRadialGradientPen = d->needsEmulation(state()->brush); } void QVGPaintEngine::brushOriginChanged() @@ -2544,6 +2595,11 @@ void QVGPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) return; } + if (d->needsEmulation(brush)) { + QPaintEngineEx::fillRect(rect, brush); + return; + } + #if !defined(QVG_NO_MODIFY_PATH) VGfloat coords[8]; if (d->simpleTransform) { @@ -2621,6 +2677,10 @@ void QVGPaintEngine::fillRect(const QRectF &rect, const QColor &color) void QVGPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode) { Q_D(QVGPaintEngine); + if (d->needsEmulation()) { + QPaintEngineEx::drawRoundedRect(rect, xrad, yrad, mode); + return; + } if (d->simpleTransform) { QVGPainterState *s = state(); VGPath vgpath = d->roundedRectPath(rect, xrad, yrad, mode); @@ -2637,6 +2697,10 @@ void QVGPaintEngine::drawRects(const QRect *rects, int rectCount) { #if !defined(QVG_NO_MODIFY_PATH) Q_D(QVGPaintEngine); + if (d->needsEmulation()) { + QPaintEngineEx::drawRects(rects, rectCount); + return; + } QVGPainterState *s = state(); for (int i = 0; i < rectCount; ++i, ++rects) { VGfloat coords[8]; @@ -2678,6 +2742,10 @@ void QVGPaintEngine::drawRects(const QRectF *rects, int rectCount) { #if !defined(QVG_NO_MODIFY_PATH) Q_D(QVGPaintEngine); + if (d->needsEmulation()) { + QPaintEngineEx::drawRects(rects, rectCount); + return; + } QVGPainterState *s = state(); for (int i = 0; i < rectCount; ++i, ++rects) { VGfloat coords[8]; @@ -2716,6 +2784,10 @@ void QVGPaintEngine::drawLines(const QLine *lines, int lineCount) { #if !defined(QVG_NO_MODIFY_PATH) Q_D(QVGPaintEngine); + if (d->needsEmulation()) { + QPaintEngineEx::drawLines(lines, lineCount); + return; + } QVGPainterState *s = state(); for (int i = 0; i < lineCount; ++i, ++lines) { VGfloat coords[4]; @@ -2744,6 +2816,10 @@ void QVGPaintEngine::drawLines(const QLineF *lines, int lineCount) { #if !defined(QVG_NO_MODIFY_PATH) Q_D(QVGPaintEngine); + if (d->needsEmulation()) { + QPaintEngineEx::drawLines(lines, lineCount); + return; + } QVGPainterState *s = state(); for (int i = 0; i < lineCount; ++i, ++lines) { VGfloat coords[4]; @@ -2773,6 +2849,10 @@ void QVGPaintEngine::drawEllipse(const QRectF &r) // Based on the description of vguEllipse() in the OpenVG specification. // We don't use vguEllipse(), to avoid unnecessary library dependencies. Q_D(QVGPaintEngine); + if (d->needsEmulation()) { + QPaintEngineEx::drawEllipse(r); + return; + } if (d->simpleTransform) { QVGPainterState *s = state(); VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, @@ -2823,6 +2903,10 @@ void QVGPaintEngine::drawPath(const QPainterPath &path) // Shortcut past the QPainterPath -> QVectorPath conversion, // converting the QPainterPath directly into a VGPath. Q_D(QVGPaintEngine); + if (d->needsEmulation()) { + QPaintEngineEx::drawPath(path); + return; + } QVGPainterState *s = state(); VGPath vgpath = d->painterPathToVGPath(path); if (path.fillRule() == Qt::OddEvenFill) @@ -2837,6 +2921,11 @@ void QVGPaintEngine::drawPoints(const QPointF *points, int pointCount) #if !defined(QVG_NO_MODIFY_PATH) Q_D(QVGPaintEngine); + if (d->needsPenEmulation()) { + QPaintEngineEx::drawPoints(points, pointCount); + return; + } + // Set up a new pen if necessary. QPen pen = state()->pen; if (pen.style() == Qt::NoPen) @@ -2871,6 +2960,11 @@ void QVGPaintEngine::drawPoints(const QPoint *points, int pointCount) #if !defined(QVG_NO_MODIFY_PATH) Q_D(QVGPaintEngine); + if (d->needsEmulation()) { + QPaintEngineEx::drawPoints(points, pointCount); + return; + } + // Set up a new pen if necessary. QPen pen = state()->pen; if (pen.style() == Qt::NoPen) @@ -2903,6 +2997,12 @@ void QVGPaintEngine::drawPoints(const QPoint *points, int pointCount) void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) { Q_D(QVGPaintEngine); + + if (d->needsEmulation()) { + QPaintEngineEx::drawPolygon(points, pointCount, mode); + return; + } + QVGPainterState *s = state(); VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, @@ -2950,6 +3050,12 @@ void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonD void QVGPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) { Q_D(QVGPaintEngine); + + if (d->needsEmulation()) { + QPaintEngineEx::drawPolygon(points, pointCount, mode); + return; + } + QVGPainterState *s = state(); VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, @@ -3596,6 +3702,11 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) return; } + if (d->needsPenEmulation()) { + QPaintEngineEx::drawTextItem(p, textItem); + return; + } + // Get the glyphs and positions associated with the text item. QVarLengthArray positions; QVarLengthArray glyphs; diff --git a/tests/arthur/common/paintcommands.cpp b/tests/arthur/common/paintcommands.cpp index 7a018e3..9273142 100644 --- a/tests/arthur/common/paintcommands.cpp +++ b/tests/arthur/common/paintcommands.cpp @@ -346,8 +346,12 @@ void PaintCommands::staticInit() "gradient_setLinear 1.0 1.0 2.0 2.0"); DECL_PAINTCOMMAND("gradient_setRadial", command_gradient_setRadial, "^gradient_setRadial\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)$", - "gradient_setRadial \n - C is the center\n - rad is the angle in degrees\n - F is the focal point", + "gradient_setRadial \n - C is the center\n - rad is the radius\n - F is the focal point", "gradient_setRadial 1.0 1.0 45.0 2.0 2.0"); + DECL_PAINTCOMMAND("gradient_setRadialExtended", command_gradient_setRadialExtended, + "^gradient_setRadialExtended\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)$", + "gradient_setRadialExtended \n - C is the center\n - rad is the center radius\n - F is the focal point\n - frad is the focal radius", + "gradient_setRadialExtended 1.0 1.0 45.0 2.0 2.0 45.0"); DECL_PAINTCOMMAND("gradient_setLinearPen", command_gradient_setLinearPen, "^gradient_setLinearPen\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)$", "gradient_setLinearPen ", @@ -2400,7 +2404,7 @@ void PaintCommands::command_gradient_setRadial(QRegExp re) double fy = convertToDouble(caps.at(5)); if (m_verboseMode) - printf(" -(lance) gradient_setRadial center=(%.2f, %.2f), radius=%.2f focal=(%.2f, %.2f), " + printf(" -(lance) gradient_setRadial center=(%.2f, %.2f), radius=%.2f, focal=(%.2f, %.2f), " "spread=%d\n", cx, cy, rad, fx, fy, m_gradientSpread); @@ -2415,6 +2419,32 @@ void PaintCommands::command_gradient_setRadial(QRegExp re) } /***************************************************************************************************/ +void PaintCommands::command_gradient_setRadialExtended(QRegExp re) +{ + QStringList caps = re.capturedTexts(); + double cx = convertToDouble(caps.at(1)); + double cy = convertToDouble(caps.at(2)); + double rad = convertToDouble(caps.at(3)); + double fx = convertToDouble(caps.at(4)); + double fy = convertToDouble(caps.at(5)); + double frad = convertToDouble(caps.at(6)); + + if (m_verboseMode) + printf(" -(lance) gradient_setRadialExtended center=(%.2f, %.2f), radius=%.2f, focal=(%.2f, %.2f), " + "focal radius=%.2f, spread=%d\n", + cx, cy, rad, fx, fy, frad, m_gradientSpread); + + QRadialGradient rg(QPointF(cx, cy), rad, QPointF(fx, fy), frad); + rg.setStops(m_gradientStops); + rg.setSpread(m_gradientSpread); + rg.setCoordinateMode(m_gradientCoordinate); + QBrush brush(rg); + QTransform brush_matrix = m_painter->brush().transform(); + brush.setTransform(brush_matrix); + m_painter->setBrush(brush); +} + +/***************************************************************************************************/ void PaintCommands::command_gradient_setConical(QRegExp re) { QStringList caps = re.capturedTexts(); diff --git a/tests/arthur/common/paintcommands.h b/tests/arthur/common/paintcommands.h index 2740412..08c0e25 100644 --- a/tests/arthur/common/paintcommands.h +++ b/tests/arthur/common/paintcommands.h @@ -179,6 +179,7 @@ private: void command_gradient_setConical(QRegExp re); void command_gradient_setLinear(QRegExp re); void command_gradient_setRadial(QRegExp re); + void command_gradient_setRadialExtended(QRegExp re); void command_gradient_setLinearPen(QRegExp re); void command_gradient_setSpread(QRegExp re); void command_gradient_setCoordinateMode(QRegExp re); diff --git a/tests/arthur/data/qps/radial_gradients_extended.qps b/tests/arthur/data/qps/radial_gradients_extended.qps new file mode 100644 index 0000000..d80a149 --- /dev/null +++ b/tests/arthur/data/qps/radial_gradients_extended.qps @@ -0,0 +1,95 @@ +path_addRect path 400 0 80 80 +path_addEllipse path 440 40 60 60 + +setRenderHint Antialiasing + +setPen black + +begin_block gradients +gradient_clearStops +gradient_appendStop 0 red +gradient_appendStop 0.25 orange +gradient_appendStop 0.5 yellow +gradient_appendStop 0.8 green +gradient_appendStop 1 cyan + +gradient_setSpread PadSpread +gradient_setRadialExtended 0 0 20 40 40 10 +drawRect 0 0 100 100 + +gradient_setSpread ReflectSpread +gradient_setRadialExtended 120 20 20 140 40 10 +drawEllipse 100 0 100 100 + +gradient_setSpread RepeatSpread +gradient_setRadialExtended 240 20 20 260 40 10 +drawRoundRect 200 0 100 100 + +gradient_clearStops +gradient_appendStop 0 3f7f7fff +gradient_appendStop 0.5 dfdfffff +gradient_appendStop 1 7f00007f + +gradient_setSpread PadSpread +gradient_setRadialExtended 320 20 20 340 40 10 +drawPolygon [300 0 390 0 350 99] + +gradient_setSpread ReflectSpread +gradient_setRadialExtended 420 20 20 440 40 10 +drawPath path + +gradient_setSpread RepeatSpread +gradient_setRadialExtended 520 20 20 540 40 10 +drawPie 500 0 100 100 720 4320 +end_block + +translate 0 100 +scale 1 2 +repeat_block gradients + +resetMatrix +translate 0 300 +brushTranslate 30 0 +brushScale 0.9 0.9 +repeat_block gradients + +# Some helpful info perhaps? +resetMatrix +setPen black + +drawText 610 50 "No XForm" +drawText 610 200 "scale 1x2" +drawText 610 300 "brush transform" +drawText 10 450 "Pad" +drawText 110 450 "Reflect" +drawText 210 450 "Repeat" +drawText 310 450 "Pad w/alpha" +drawText 410 450 "Reflect w/alpha" +drawText 510 450 "Repeat w/alpha" + +# Radius and focal indicators +setPen 3f000000 +setBrush nobrush + +begin_block ellipse_draw +setClipRect 0 0 100 100 +drawEllipse -30 -30 100 100 +drawEllipse 35 35 11 11 +translate 100 0 +end_block + +repeat_block ellipse_draw +repeat_block ellipse_draw +repeat_block ellipse_draw +repeat_block ellipse_draw +repeat_block ellipse_draw + +resetMatrix +translate 0 100 +scale 1 2 +repeat_block ellipse_draw +repeat_block ellipse_draw +repeat_block ellipse_draw +repeat_block ellipse_draw +repeat_block ellipse_draw +repeat_block ellipse_draw diff --git a/tests/arthur/data/qps/radial_gradients_extended_qps.png b/tests/arthur/data/qps/radial_gradients_extended_qps.png new file mode 100644 index 0000000..45a3e60 Binary files /dev/null and b/tests/arthur/data/qps/radial_gradients_extended_qps.png differ -- cgit v0.12 From f7b60fffb673b182e633545bffd1d310337aca50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20G=C3=A2teau?= Date: Thu, 14 Apr 2011 10:00:18 +0200 Subject: Fix warning about initialization order Merge-request: 916 Reviewed-by: Thierry Bastian --- src/gui/widgets/qmenu_p.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/widgets/qmenu_p.h b/src/gui/widgets/qmenu_p.h index 005ce1d..9fd55ca 100644 --- a/src/gui/widgets/qmenu_p.h +++ b/src/gui/widgets/qmenu_p.h @@ -154,6 +154,9 @@ public: #endif scroll(0), eventLoop(0), tearoff(0), tornoff(0), tearoffHighlighted(0), hasCheckableItems(0), sloppyAction(0), doChildEffects(false) +#ifdef QT3_SUPPORT + ,emitHighlighted(false) +#endif #ifdef Q_WS_MAC ,mac_menu(0) #endif @@ -163,9 +166,6 @@ public: #ifdef Q_WS_S60 ,symbian_menu(0) #endif -#ifdef QT3_SUPPORT - ,emitHighlighted(false) -#endif { } ~QMenuPrivate() { -- cgit v0.12 From c664954295c0605c73f7e69deb9f6130c5f5fb05 Mon Sep 17 00:00:00 2001 From: Aurelien Gateau Date: Thu, 14 Apr 2011 10:00:21 +0200 Subject: Hide QMenuAction This will help abstracting the platform specific parts of QMenuBarPrivate in a common interface. Merge-request: 916 Reviewed-by: Thierry Bastian --- src/gui/widgets/qmenu_mac.mm | 4 ++-- src/gui/widgets/qmenu_symbian.cpp | 4 ++-- src/gui/widgets/qmenu_wince.cpp | 4 ++-- src/gui/widgets/qmenubar.cpp | 2 +- src/gui/widgets/qmenubar_p.h | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/gui/widgets/qmenu_mac.mm b/src/gui/widgets/qmenu_mac.mm index 2977558..f780ee7 100644 --- a/src/gui/widgets/qmenu_mac.mm +++ b/src/gui/widgets/qmenu_mac.mm @@ -1639,7 +1639,7 @@ QMenuBarPrivate::QMacMenuBarPrivate::~QMacMenuBarPrivate() } void -QMenuBarPrivate::QMacMenuBarPrivate::addAction(QAction *a, QMacMenuAction *before) +QMenuBarPrivate::QMacMenuBarPrivate::addAction(QAction *a, QAction *before) { if (a->isSeparator() || !menu) return; @@ -1649,7 +1649,7 @@ QMenuBarPrivate::QMacMenuBarPrivate::addAction(QAction *a, QMacMenuAction *befor #ifndef QT_MAC_USE_COCOA action->command = qt_mac_menu_static_cmd_id++; #endif - addAction(action, before); + addAction(action, findAction(before)); } void diff --git a/src/gui/widgets/qmenu_symbian.cpp b/src/gui/widgets/qmenu_symbian.cpp index d614bb8..12c6c6e 100644 --- a/src/gui/widgets/qmenu_symbian.cpp +++ b/src/gui/widgets/qmenu_symbian.cpp @@ -398,12 +398,12 @@ void QMenuPrivate::QSymbianMenuPrivate::rebuild(bool) { } -void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QAction *a, QSymbianMenuAction *before) +void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QAction *a, QAction *before) { QSymbianMenuAction *action = new QSymbianMenuAction; action->action = a; action->command = qt_symbian_menu_static_cmd_id++; - addAction(action, before); + addAction(action, findAction(before)); } void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before) diff --git a/src/gui/widgets/qmenu_wince.cpp b/src/gui/widgets/qmenu_wince.cpp index 86a78ad..2210409 100644 --- a/src/gui/widgets/qmenu_wince.cpp +++ b/src/gui/widgets/qmenu_wince.cpp @@ -504,12 +504,12 @@ void QMenuPrivate::QWceMenuPrivate::removeAction(QWceMenuAction *action) rebuild(); } -void QMenuBarPrivate::QWceMenuBarPrivate::addAction(QAction *a, QWceMenuAction *before) +void QMenuBarPrivate::QWceMenuBarPrivate::addAction(QAction *a, QAction *before) { QWceMenuAction *action = new QWceMenuAction; action->action = a; action->command = qt_wce_menu_static_cmd_id++; - addAction(action, before); + addAction(action, findAction(before)); } void QMenuBarPrivate::QWceMenuBarPrivate::addAction(QWceMenuAction *action, QWceMenuAction *before) diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index 5bfac9a..08c287e 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -1287,7 +1287,7 @@ void QMenuBar::actionEvent(QActionEvent *e) if (!nativeMenuBar) return; if(e->type() == QEvent::ActionAdded) - nativeMenuBar->addAction(e->action(), nativeMenuBar->findAction(e->before())); + nativeMenuBar->addAction(e->action(), e->before()); else if(e->type() == QEvent::ActionRemoved) nativeMenuBar->removeAction(e->action()); else if(e->type() == QEvent::ActionChanged) diff --git a/src/gui/widgets/qmenubar_p.h b/src/gui/widgets/qmenubar_p.h index 5afe713..2b8558b 100644 --- a/src/gui/widgets/qmenubar_p.h +++ b/src/gui/widgets/qmenubar_p.h @@ -181,7 +181,7 @@ public: QMacMenuBarPrivate(); ~QMacMenuBarPrivate(); - void addAction(QAction *, QMacMenuAction* =0); + void addAction(QAction *, QAction* =0); void addAction(QMacMenuAction *, QMacMenuAction* =0); void syncAction(QMacMenuAction *); inline void syncAction(QAction *a) { syncAction(findAction(a)); } @@ -220,7 +220,7 @@ public: QWceMenuBarPrivate(QMenuBarPrivate *menubar); ~QWceMenuBarPrivate(); - void addAction(QAction *, QWceMenuAction* =0); + void addAction(QAction *, QAction* =0); void addAction(QWceMenuAction *, QWceMenuAction* =0); void syncAction(QWceMenuAction *); inline void syncAction(QAction *a) { syncAction(findAction(a)); } @@ -250,7 +250,7 @@ public: QMenuBarPrivate *d; QSymbianMenuBarPrivate(QMenuBarPrivate *menubar); ~QSymbianMenuBarPrivate(); - void addAction(QAction *, QSymbianMenuAction* =0); + void addAction(QAction *, QAction* =0); void addAction(QSymbianMenuAction *, QSymbianMenuAction* =0); void syncAction(QSymbianMenuAction *); inline void syncAction(QAction *a) { syncAction(findAction(a)); } -- cgit v0.12 From 0432a6b79d35ac7db909a81793417107ebfb668f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20G=C3=A2teau?= Date: Thu, 14 Apr 2011 10:00:24 +0200 Subject: Introduce QAbstractMenuBarImpl Merge-request: 916 Reviewed-by: Thierry Bastian --- src/gui/widgets/qabstractmenubarimpl_p.cpp | 44 +++++ src/gui/widgets/qabstractmenubarimpl_p.h | 104 +++++++++++ src/gui/widgets/qmenubar.cpp | 287 +++++++++++------------------ src/gui/widgets/qmenubar_p.h | 129 ++----------- src/gui/widgets/qmenubarimpl.cpp | 244 ++++++++++++++++++++++++ src/gui/widgets/qmenubarimpl_p.h | 182 ++++++++++++++++++ src/gui/widgets/widgets.pri | 3 + 7 files changed, 694 insertions(+), 299 deletions(-) create mode 100644 src/gui/widgets/qabstractmenubarimpl_p.cpp create mode 100644 src/gui/widgets/qabstractmenubarimpl_p.h create mode 100644 src/gui/widgets/qmenubarimpl.cpp create mode 100644 src/gui/widgets/qmenubarimpl_p.h diff --git a/src/gui/widgets/qabstractmenubarimpl_p.cpp b/src/gui/widgets/qabstractmenubarimpl_p.cpp new file mode 100644 index 0000000..bc16030 --- /dev/null +++ b/src/gui/widgets/qabstractmenubarimpl_p.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include + +QAbstractMenuBarImpl::~QAbstractMenuBarImpl() +{} diff --git a/src/gui/widgets/qabstractmenubarimpl_p.h b/src/gui/widgets/qabstractmenubarimpl_p.h new file mode 100644 index 0000000..d001008 --- /dev/null +++ b/src/gui/widgets/qabstractmenubarimpl_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QABSTRACTMENUBARIMPL_P_H +#define QABSTRACTMENUBARIMPL_P_H + +#include + +#ifndef QT_NO_MENUBAR + +QT_BEGIN_NAMESPACE + +class QAction; +class QActionEvent; +class QEvent; +class QMenuBar; +class QObject; +class QWidget; + +/** + * The platform-specific implementation of a menubar + */ +class Q_GUI_EXPORT QAbstractMenuBarImpl +{ +public: + virtual ~QAbstractMenuBarImpl(); + + // QMenuBarPrivate::init() + virtual void init(QMenuBar *) = 0; + + // QMenuBar::setVisible() + virtual bool allowSetVisible() const = 0; + + virtual void actionEvent(QActionEvent *) = 0; + + // QMenuBar::handleReparent() + virtual void handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow) = 0; + + // QMenuBarPrivate::updateGeometries() + // QMenuBar::minimumSizeHint() + // QMenuBar::sizeHint() + // QMenuBar::heightForWidth() + virtual bool allowCornerWidgets() const = 0; + + // QMenuBar::_q_internalShortcutActivated() + virtual void popupAction(QAction*) = 0; + + // QMenuBar::setNativeMenuBar() + virtual void setNativeMenuBar(bool) = 0; + + virtual bool isNativeMenuBar() const = 0; + + /** + * Return true if the native menubar is capable of listening to the + * shortcut keys. If false is returned, QMenuBar will trigger actions on + * shortcut itself. + */ + virtual bool shortcutsHandledByNativeMenuBar() const = 0; + + virtual bool menuBarEventFilter(QObject *, QEvent *event) = 0; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_MENUBAR + +#endif // QABSTRACTMENUBARIMPL_P_H diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index 08c287e..0d13574 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -63,9 +63,10 @@ #include #endif +#include "qdebug.h" #include "qmenu_p.h" #include "qmenubar_p.h" -#include "qdebug.h" +#include "qmenubarimpl_p.h" #ifdef Q_WS_WINCE extern bool qt_wince_is_mobile(); //defined in qguifunctions_wce.cpp @@ -173,7 +174,8 @@ void QMenuBarPrivate::updateGeometries() return; int q_width = q->width()-(q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q)*2); int q_start = -1; - if(leftWidget || rightWidget) { + + if(impl->allowCornerWidgets() && (leftWidget || rightWidget)) { int vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, q) + q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q); int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarHMargin, 0, q) @@ -195,16 +197,8 @@ void QMenuBarPrivate::updateGeometries() } } -#ifdef Q_WS_MAC - if(q->isNativeMenuBar()) {//nothing to see here folks, move along.. - itemsDirty = false; - return; - } -#endif - calcActionRects(q_width, q_start); - currentAction = 0; #ifndef QT_NO_SHORTCUT - if(itemsDirty) { + if(!impl->shortcutsHandledByNativeMenuBar() && itemsDirty) { for(int j = 0; j < shortcutIndexMap.size(); ++j) q->releaseShortcut(shortcutIndexMap.value(j)); shortcutIndexMap.resize(0); // faster than clear @@ -212,6 +206,12 @@ void QMenuBarPrivate::updateGeometries() shortcutIndexMap.append(q->grabShortcut(QKeySequence::mnemonic(actions.at(i)->text()))); } #endif + if(q->isNativeMenuBar()) {//nothing to see here folks, move along.. + itemsDirty = false; + return; + } + calcActionRects(q_width, q_start); + currentAction = 0; itemsDirty = false; hiddenActions.clear(); @@ -728,21 +728,9 @@ void QMenuBarPrivate::init() Q_Q(QMenuBar); q->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); q->setAttribute(Qt::WA_CustomWhatsThis); -#ifdef Q_WS_MAC - macCreateMenuBar(q->parentWidget()); - if(mac_menubar) - q->hide(); -#endif -#ifdef Q_WS_WINCE - if (qt_wince_is_mobile()) { - wceCreateMenuBar(q->parentWidget()); - if(wce_menubar) - q->hide(); - } - else { - QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true); - } -#endif + impl = new QMenuBarImpl; + impl->init(q); + q->setBackgroundRole(QPalette::Button); oldWindow = oldParent = 0; #ifdef QT3_SUPPORT @@ -751,6 +739,9 @@ void QMenuBarPrivate::init() #ifdef QT_SOFTKEYS_ENABLED menuBarAction = 0; #endif + cornerWidgetToolBar = 0; + cornerWidgetContainer = 0; + handleReparent(); q->setMouseTracking(q->style()->styleHint(QStyle::SH_MenuBar_MouseTracking, 0, q)); @@ -808,19 +799,8 @@ QMenuBar::QMenuBar(QWidget *parent, const char *name) : QWidget(*new QMenuBarPri */ QMenuBar::~QMenuBar() { -#ifdef Q_WS_MAC - Q_D(QMenuBar); - d->macDestroyMenuBar(); -#endif -#ifdef Q_WS_WINCE Q_D(QMenuBar); - if (qt_wince_is_mobile()) - d->wceDestroyMenuBar(); -#endif -#ifdef Q_WS_S60 - Q_D(QMenuBar); - d->symbianDestroyMenuBar(); -#endif + delete d->cornerWidgetToolBar; } /*! @@ -1072,13 +1052,10 @@ void QMenuBar::paintEvent(QPaintEvent *e) */ void QMenuBar::setVisible(bool visible) { -#if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) - if (isNativeMenuBar()) { - if (!visible) - QWidget::setVisible(false); + Q_D(QMenuBar); + if (!d->impl->allowSetVisible()) { return; } -#endif QWidget::setVisible(visible); } @@ -1275,25 +1252,7 @@ void QMenuBar::actionEvent(QActionEvent *e) { Q_D(QMenuBar); d->itemsDirty = true; -#if defined (Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) - if (isNativeMenuBar()) { -#ifdef Q_WS_MAC - QMenuBarPrivate::QMacMenuBarPrivate *nativeMenuBar = d->mac_menubar; -#elif defined(Q_WS_S60) - QMenuBarPrivate::QSymbianMenuBarPrivate *nativeMenuBar = d->symbian_menubar; -#else - QMenuBarPrivate::QWceMenuBarPrivate *nativeMenuBar = d->wce_menubar; -#endif - if (!nativeMenuBar) - return; - if(e->type() == QEvent::ActionAdded) - nativeMenuBar->addAction(e->action(), e->before()); - else if(e->type() == QEvent::ActionRemoved) - nativeMenuBar->removeAction(e->action()); - else if(e->type() == QEvent::ActionChanged) - nativeMenuBar->syncAction(e->action()); - } -#endif + d->impl->actionEvent(e); if(e->type() == QEvent::ActionAdded) { connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered())); @@ -1369,55 +1328,10 @@ void QMenuBarPrivate::handleReparent() newWindow->installEventFilter(q); } + impl->handleReparent(oldParent, newParent, oldWindow, newWindow); + oldParent = newParent; oldWindow = newWindow; - -#ifdef Q_WS_MAC - if (q->isNativeMenuBar() && !macWidgetHasNativeMenubar(newParent)) { - // If the new parent got a native menubar from before, keep that - // menubar rather than replace it with this one (because a parents - // menubar has precedence over children menubars). - macDestroyMenuBar(); - macCreateMenuBar(newParent); - } -#endif - -#ifdef Q_WS_WINCE - if (qt_wince_is_mobile() && wce_menubar) - wce_menubar->rebuild(); -#endif -#ifdef Q_WS_S60 - - // Construct symbian_menubar when this code path is entered first time - // and when newParent != NULL - if (!symbian_menubar) - symbianCreateMenuBar(newParent); - - // Reparent and rebuild menubar when parent is changed - if (symbian_menubar) { - if (oldParent != newParent) - reparentMenuBar(oldParent, newParent); - q->hide(); - symbian_menubar->rebuild(); - } - -#ifdef QT_SOFTKEYS_ENABLED - // Constuct menuBarAction when this code path is entered first time - if (!menuBarAction) { - if (newParent) { - menuBarAction = QSoftKeyManager::createAction(QSoftKeyManager::MenuSoftKey, newParent); - newParent->addAction(menuBarAction); - } - } else { - // If reparenting i.e. we already have menuBarAction, remove it from old parent - // and add for a new parent - if (oldParent) - oldParent->removeAction(menuBarAction); - if (newParent) - newParent->addAction(menuBarAction); - } -#endif // QT_SOFTKEYS_ENABLED -#endif // Q_WS_S60 } #ifdef QT3_SUPPORT @@ -1566,6 +1480,9 @@ bool QMenuBar::event(QEvent *e) bool QMenuBar::eventFilter(QObject *object, QEvent *event) { Q_D(QMenuBar); + if (d->impl->menuBarEventFilter(object, event)) { + return true; + } if (object == parent() && object) { #ifdef QT3_SUPPORT if (d->doAutoResize && event->type() == QEvent::Resize) { @@ -1659,11 +1576,7 @@ QRect QMenuBar::actionGeometry(QAction *act) const QSize QMenuBar::minimumSizeHint() const { Q_D(const QMenuBar); -#if defined(Q_WS_MAC) || defined(Q_WS_WINCE) || defined(Q_WS_S60) const bool as_gui_menubar = !isNativeMenuBar(); -#else - const bool as_gui_menubar = true; -#endif ensurePolished(); QSize ret(0, 0); @@ -1682,17 +1595,19 @@ QSize QMenuBar::minimumSizeHint() const ret += QSize(2*fw + hmargin, 2*fw + vmargin); } int margin = 2*vmargin + 2*fw + spaceBelowMenuBar; - if(d->leftWidget) { - QSize sz = d->leftWidget->minimumSizeHint(); - ret.setWidth(ret.width() + sz.width()); - if(sz.height() + margin > ret.height()) - ret.setHeight(sz.height() + margin); - } - if(d->rightWidget) { - QSize sz = d->rightWidget->minimumSizeHint(); - ret.setWidth(ret.width() + sz.width()); - if(sz.height() + margin > ret.height()) - ret.setHeight(sz.height() + margin); + if (d->impl->allowCornerWidgets()) { + if(d->leftWidget) { + QSize sz = d->leftWidget->minimumSizeHint(); + ret.setWidth(ret.width() + sz.width()); + if(sz.height() + margin > ret.height()) + ret.setHeight(sz.height() + margin); + } + if(d->rightWidget) { + QSize sz = d->rightWidget->minimumSizeHint(); + ret.setWidth(ret.width() + sz.width()); + if(sz.height() + margin > ret.height()) + ret.setHeight(sz.height() + margin); + } } if(as_gui_menubar) { QStyleOptionMenuItem opt; @@ -1715,12 +1630,7 @@ QSize QMenuBar::minimumSizeHint() const QSize QMenuBar::sizeHint() const { Q_D(const QMenuBar); -#if defined(Q_WS_MAC) || defined(Q_WS_WINCE) || defined(Q_WS_S60) const bool as_gui_menubar = !isNativeMenuBar(); -#else - const bool as_gui_menubar = true; -#endif - ensurePolished(); QSize ret(0, 0); @@ -1741,17 +1651,19 @@ QSize QMenuBar::sizeHint() const ret += QSize(fw + hmargin, fw + vmargin); } int margin = 2*vmargin + 2*fw + spaceBelowMenuBar; - if(d->leftWidget) { - QSize sz = d->leftWidget->sizeHint(); - ret.setWidth(ret.width() + sz.width()); - if(sz.height() + margin > ret.height()) - ret.setHeight(sz.height() + margin); - } - if(d->rightWidget) { - QSize sz = d->rightWidget->sizeHint(); - ret.setWidth(ret.width() + sz.width()); - if(sz.height() + margin > ret.height()) - ret.setHeight(sz.height() + margin); + if(d->impl->allowCornerWidgets()) { + if(d->leftWidget) { + QSize sz = d->leftWidget->sizeHint(); + ret.setWidth(ret.width() + sz.width()); + if(sz.height() + margin > ret.height()) + ret.setHeight(sz.height() + margin); + } + if(d->rightWidget) { + QSize sz = d->rightWidget->sizeHint(); + ret.setWidth(ret.width() + sz.width()); + if(sz.height() + margin > ret.height()) + ret.setHeight(sz.height() + margin); + } } if(as_gui_menubar) { QStyleOptionMenuItem opt; @@ -1774,11 +1686,7 @@ QSize QMenuBar::sizeHint() const int QMenuBar::heightForWidth(int) const { Q_D(const QMenuBar); -#if defined(Q_WS_MAC) || defined(Q_WS_WINCE) || defined(Q_WS_S60) const bool as_gui_menubar = !isNativeMenuBar(); -#else - const bool as_gui_menubar = true; -#endif const_cast(d)->updateGeometries(); int height = 0; @@ -1794,10 +1702,12 @@ int QMenuBar::heightForWidth(int) const height += 2*vmargin; } int margin = 2*vmargin + 2*fw + spaceBelowMenuBar; - if(d->leftWidget) - height = qMax(d->leftWidget->sizeHint().height() + margin, height); - if(d->rightWidget) - height = qMax(d->rightWidget->sizeHint().height() + margin, height); + if(d->impl->allowCornerWidgets()) { + if(d->leftWidget) + height = qMax(d->leftWidget->sizeHint().height() + margin, height); + if(d->rightWidget) + height = qMax(d->rightWidget->sizeHint().height() + margin, height); + } if(as_gui_menubar) { QStyleOptionMenuItem opt; opt.init(this); @@ -1817,7 +1727,11 @@ void QMenuBarPrivate::_q_internalShortcutActivated(int id) { Q_Q(QMenuBar); QAction *act = actions.at(id); - setCurrentAction(act, true, true); + if (q->isNativeMenuBar()) { + impl->popupAction(act); + } else { + setCurrentAction(act, true, true); + } if (act && !act->menu()) { activateAction(act, QAction::Trigger); //100 is the same as the default value in QPushButton::animateClick @@ -1838,6 +1752,37 @@ void QMenuBarPrivate::_q_updateLayout() } } +void QMenuBarPrivate::updateCornerWidgetToolBar() +{ + Q_Q(QMenuBar); + if (!cornerWidgetToolBar) { + QMainWindow *window = qobject_cast(q->window()); + if (!window) { + qWarning() << "Menubar parent is not a QMainWindow, not showing corner widgets"; + return; + } + cornerWidgetToolBar = window->addToolBar(QApplication::translate("QMenuBar", "Corner Toolbar")); + cornerWidgetToolBar->setObjectName(QLatin1String("CornerToolBar")); + cornerWidgetContainer = new QWidget; + cornerWidgetToolBar->addWidget(cornerWidgetContainer); + new QHBoxLayout(cornerWidgetContainer); + } else { + QLayout *layout = cornerWidgetContainer->layout(); + while (layout->count() > 0) { + layout->takeAt(0); + } + } + if (leftWidget) { + leftWidget->setParent(cornerWidgetContainer); + cornerWidgetContainer->layout()->addWidget(leftWidget); + } + if (rightWidget) { + rightWidget->setParent(cornerWidgetContainer); + cornerWidgetContainer->layout()->addWidget(rightWidget); + } +} + + /*! \fn void QMenuBar::setCornerWidget(QWidget *widget, Qt::Corner corner) @@ -1870,9 +1815,13 @@ void QMenuBar::setCornerWidget(QWidget *w, Qt::Corner corner) return; } - if (w) { - w->setParent(this); - w->installEventFilter(this); + if(!d->impl->allowCornerWidgets()) { + d->updateCornerWidgetToolBar(); + } else { + if (w) { + w->setParent(this); + w->installEventFilter(this); + } } d->_q_updateLayout(); @@ -1923,39 +1872,13 @@ QWidget *QMenuBar::cornerWidget(Qt::Corner corner) const void QMenuBar::setNativeMenuBar(bool nativeMenuBar) { Q_D(QMenuBar); - if (d->nativeMenuBar == -1 || (nativeMenuBar != bool(d->nativeMenuBar))) { - d->nativeMenuBar = nativeMenuBar; -#ifdef Q_WS_MAC - if (!d->nativeMenuBar) { - extern void qt_mac_clear_menubar(); - qt_mac_clear_menubar(); - d->macDestroyMenuBar(); - const QList &menubarActions = actions(); - for (int i = 0; i < menubarActions.size(); ++i) { - const QAction *action = menubarActions.at(i); - if (QMenu *menu = action->menu()) { - delete menu->d_func()->mac_menu; - menu->d_func()->mac_menu = 0; - } - } - } else { - d->macCreateMenuBar(parentWidget()); - } - macUpdateMenuBar(); - updateGeometry(); - if (!d->nativeMenuBar && parentWidget()) - setVisible(true); -#endif - } + d->impl->setNativeMenuBar(nativeMenuBar); } bool QMenuBar::isNativeMenuBar() const { Q_D(const QMenuBar); - if (d->nativeMenuBar == -1) { - return !QApplication::instance()->testAttribute(Qt::AA_DontUseNativeMenuBar); - } - return d->nativeMenuBar; + return d->impl->isNativeMenuBar(); } /*! @@ -1992,8 +1915,8 @@ void QMenuBar::setDefaultAction(QAction *act) connect(d->defaultAction, SIGNAL(changed()), this, SLOT(_q_updateDefaultAction())); connect(d->defaultAction, SIGNAL(destroyed()), this, SLOT(_q_updateDefaultAction())); } - if (d->wce_menubar) { - d->wce_menubar->rebuild(); + if (d->impl->nativeMenuBarAdapter()) { + d->impl->nativeMenuBarAdapter()->rebuild(); } #endif } diff --git a/src/gui/widgets/qmenubar_p.h b/src/gui/widgets/qmenubar_p.h index 2b8558b..b49e039 100644 --- a/src/gui/widgets/qmenubar_p.h +++ b/src/gui/widgets/qmenubar_p.h @@ -61,6 +61,8 @@ #include "qguifunctions_wince.h" #endif +#include "qabstractmenubarimpl_p.h" + #ifndef QT_NO_MENUBAR #ifdef Q_WS_S60 class CCoeControl; @@ -71,6 +73,7 @@ class CEikMenuBar; QT_BEGIN_NAMESPACE #ifndef QT_NO_MENUBAR +class QToolBar; class QMenuBarExtension; class QMenuBarPrivate : public QWidgetPrivate { @@ -78,33 +81,19 @@ class QMenuBarPrivate : public QWidgetPrivate public: QMenuBarPrivate() : itemsDirty(0), currentAction(0), mouseDown(0), closePopupMode(0), defaultPopDown(1), popupState(0), keyboardState(0), altPressed(0), - nativeMenuBar(-1), doChildEffects(false) + doChildEffects(false) #ifdef QT3_SUPPORT , doAutoResize(false) #endif -#ifdef Q_WS_MAC - , mac_menubar(0) -#endif - + , impl(0) #ifdef Q_WS_WINCE - , wce_menubar(0), wceClassicMenu(false) -#endif -#ifdef Q_WS_S60 - , symbian_menubar(0) + , wceClassicMenu(false) #endif { } ~QMenuBarPrivate() { -#ifdef Q_WS_MAC - delete mac_menubar; -#endif -#ifdef Q_WS_WINCE - delete wce_menubar; -#endif -#ifdef Q_WS_S60 - delete symbian_menubar; -#endif + delete impl; } void init(); @@ -136,8 +125,6 @@ public: uint keyboardState : 1, altPressed : 1; QPointer keyboardFocusWidget; - - int nativeMenuBar : 3; // Only has values -1, 0, and 1 //firing of events void activateAction(QAction *, QAction::ActionEvent); @@ -173,106 +160,14 @@ public: #ifdef QT3_SUPPORT bool doAutoResize; #endif -#ifdef Q_WS_MAC - //mac menubar binding - struct QMacMenuBarPrivate { - QList actionItems; - OSMenuRef menu, apple_menu; - QMacMenuBarPrivate(); - ~QMacMenuBarPrivate(); - - void addAction(QAction *, QAction* =0); - void addAction(QMacMenuAction *, QMacMenuAction* =0); - void syncAction(QMacMenuAction *); - inline void syncAction(QAction *a) { syncAction(findAction(a)); } - void removeAction(QMacMenuAction *); - inline void removeAction(QAction *a) { removeAction(findAction(a)); } - inline QMacMenuAction *findAction(QAction *a) { - for(int i = 0; i < actionItems.size(); i++) { - QMacMenuAction *act = actionItems[i]; - if(a == act->action) - return act; - } - return 0; - } - } *mac_menubar; - static bool macUpdateMenuBarImmediatly(); - bool macWidgetHasNativeMenubar(QWidget *widget); - void macCreateMenuBar(QWidget *); - void macDestroyMenuBar(); - OSMenuRef macMenu(); -#endif -#ifdef Q_WS_WINCE - void wceCreateMenuBar(QWidget *); - void wceDestroyMenuBar(); - struct QWceMenuBarPrivate { - QList actionItems; - QList actionItemsLeftButton; - QList> actionItemsClassic; - HMENU menuHandle; - HMENU leftButtonMenuHandle; - HWND menubarHandle; - HWND parentWindowHandle; - bool leftButtonIsMenu; - QPointer leftButtonAction; - QMenuBarPrivate *d; - int leftButtonCommand; - - QWceMenuBarPrivate(QMenuBarPrivate *menubar); - ~QWceMenuBarPrivate(); - void addAction(QAction *, QAction* =0); - void addAction(QWceMenuAction *, QWceMenuAction* =0); - void syncAction(QWceMenuAction *); - inline void syncAction(QAction *a) { syncAction(findAction(a)); } - void removeAction(QWceMenuAction *); - void rebuild(); - inline void removeAction(QAction *a) { removeAction(findAction(a)); } - inline QWceMenuAction *findAction(QAction *a) { - for(int i = 0; i < actionItems.size(); i++) { - QWceMenuAction *act = actionItems[i]; - if(a == act->action) - return act; - } - return 0; - } - } *wce_menubar; - bool wceClassicMenu; - void wceCommands(uint command); - void wceRefresh(); - bool wceEmitSignals(QList actions, uint command); -#endif -#ifdef Q_WS_S60 - void symbianCreateMenuBar(QWidget *); - void symbianDestroyMenuBar(); - void reparentMenuBar(QWidget *oldParent, QWidget *newParent); - struct QSymbianMenuBarPrivate { - QList actionItems; - QMenuBarPrivate *d; - QSymbianMenuBarPrivate(QMenuBarPrivate *menubar); - ~QSymbianMenuBarPrivate(); - void addAction(QAction *, QAction* =0); - void addAction(QSymbianMenuAction *, QSymbianMenuAction* =0); - void syncAction(QSymbianMenuAction *); - inline void syncAction(QAction *a) { syncAction(findAction(a)); } - void removeAction(QSymbianMenuAction *); - void rebuild(); - inline void removeAction(QAction *a) { removeAction(findAction(a)); } - inline QSymbianMenuAction *findAction(QAction *a) { - for(int i = 0; i < actionItems.size(); i++) { - QSymbianMenuAction *act = actionItems[i]; - if(a == act->action) - return act; - } - return 0; - } - void insertNativeMenuItems(const QList &actions); - - } *symbian_menubar; - static int symbianCommands(int command); -#endif + QAbstractMenuBarImpl *impl; #ifdef QT_SOFTKEYS_ENABLED QAction *menuBarAction; #endif + + void updateCornerWidgetToolBar(); + QToolBar *cornerWidgetToolBar; + QWidget *cornerWidgetContainer; }; #endif diff --git a/src/gui/widgets/qmenubarimpl.cpp b/src/gui/widgets/qmenubarimpl.cpp new file mode 100644 index 0000000..195f0ea --- /dev/null +++ b/src/gui/widgets/qmenubarimpl.cpp @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qmenubarimpl_p.h" + +#ifndef QT_NO_MENUBAR + +#include "qapplication.h" +#include "qdebug.h" +#include "qevent.h" +#include "qmenu.h" +#include "qmenubar.h" + +QT_BEGIN_NAMESPACE + +QMenuBarImpl::~QMenuBarImpl() +{ +#ifdef Q_WS_MAC + macDestroyMenuBar(); +#endif +#ifdef Q_WS_WINCE + if (qt_wince_is_mobile()) + wceDestroyMenuBar(); +#endif +#ifdef Q_WS_S60 + symbianDestroyMenuBar(); +#endif +} + +void QMenuBarImpl::init(QMenuBar *_menuBar) +{ + nativeMenuBar = -1; + menuBar = _menuBar; +#if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) + adapter = 0; +#endif +#ifdef Q_WS_MAC + macCreateMenuBar(menuBar->parentWidget()); + if(adapter) + menuBar->hide(); +#endif +#ifdef Q_WS_WINCE + if (qt_wince_is_mobile()) { + wceCreateMenuBar(menuBar->parentWidget()); + if(adapter) + menuBar->hide(); + } + else { + QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true); + } +#endif +} + +bool QMenuBarImpl::allowSetVisible() const +{ +#if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) + // FIXME: Port this to a setVisible() method + /* + if (isNativeMenuBar()) { + if (!visible) + QWidget::setVisible(false); + return; + } + */ + return !isNativeMenuBar(); +#endif + return true; +} + +void QMenuBarImpl::actionEvent(QActionEvent *e) +{ +#if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) + if (adapter) { + if(e->type() == QEvent::ActionAdded) + adapter->addAction(e->action(), e->before()); + else if(e->type() == QEvent::ActionRemoved) + adapter->removeAction(e->action()); + else if(e->type() == QEvent::ActionChanged) + adapter->syncAction(e->action()); + } +#else + Q_UNUSED(e); +#endif +} + +void QMenuBarImpl::handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow) +{ +#ifdef Q_WS_X11 + Q_UNUSED(oldParent) + Q_UNUSED(newParent) + Q_UNUSED(oldWindow) + Q_UNUSED(newWindow) +#endif + +#ifdef Q_WS_MAC + if (isNativeMenuBar() && !macWidgetHasNativeMenubar(newParent)) { + // If the new parent got a native menubar from before, keep that + // menubar rather than replace it with this one (because a parents + // menubar has precedence over children menubars). + macDestroyMenuBar(); + macCreateMenuBar(newParent); + } +#endif +#ifdef Q_WS_WINCE + if (qt_wince_is_mobile() && nativeMenuBarAdapter()) + adapter->rebuild(); +#endif +#ifdef Q_WS_S60 + + // Construct d->impl->nativeMenuBarAdapter() when this code path is entered first time + // and when newParent != NULL + if (!adapter) + symbianCreateMenuBar(newParent); + + // Reparent and rebuild menubar when parent is changed + if (adapter) { + if (oldParent != newParent) + reparentMenuBar(oldParent, newParent); + menuBar->hide(); + adapter->rebuild(); + } + +#ifdef QT_SOFTKEYS_ENABLED + // Constuct menuBarAction when this code path is entered first time + if (!menuBarAction) { + if (newParent) { + menuBarAction = QSoftKeyManager::createAction(QSoftKeyManager::MenuSoftKey, newParent); + newParent->addAction(menuBarAction); + } + } else { + // If reparenting i.e. we already have menuBarAction, remove it from old parent + // and add for a new parent + if (oldParent) + oldParent->removeAction(menuBarAction); + if (newParent) + newParent->addAction(menuBarAction); + } +#endif // QT_SOFTKEYS_ENABLED +#endif // Q_WS_S60 +} + +bool QMenuBarImpl::allowCornerWidgets() const +{ + return true; +} + +void QMenuBarImpl::popupAction(QAction *) +{ +} + +void QMenuBarImpl::setNativeMenuBar(bool value) +{ + if (nativeMenuBar == -1 || (value != bool(nativeMenuBar))) { + nativeMenuBar = value; +#ifdef Q_WS_MAC + if (!nativeMenuBar) { + extern void qt_mac_clear_menubar(); + qt_mac_clear_menubar(); + macDestroyMenuBar(); + const QList &menubarActions = actions(); + for (int i = 0; i < menubarActions.size(); ++i) { + const QAction *action = menubarActions.at(i); + if (QMenu *menu = action->menu()) { + delete menu->d_func()->mac_menu; + menu->d_func()->mac_menu = 0; + } + } + } else { + macCreateMenuBar(parentWidget()); + } + macUpdateMenuBar(); + updateGeometry(); + if (!nativeMenuBar && parentWidget()) + setVisible(true); +#endif + } +} + +bool QMenuBarImpl::isNativeMenuBar() const +{ +#if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) + if (nativeMenuBar == -1) { + return !QApplication::instance()->testAttribute(Qt::AA_DontUseNativeMenuBar); + } + return nativeMenuBar; +#else + return false; +#endif +} + +bool QMenuBarImpl::shortcutsHandledByNativeMenuBar() const +{ +#ifdef Q_WS_MAC + return true; +#else + return false; +#endif +} + +bool QMenuBarImpl::menuBarEventFilter(QObject *, QEvent *) +{ + return false; +} + +QT_END_NAMESPACE + +#endif // QT_NO_MENUBAR diff --git a/src/gui/widgets/qmenubarimpl_p.h b/src/gui/widgets/qmenubarimpl_p.h new file mode 100644 index 0000000..e770b5b --- /dev/null +++ b/src/gui/widgets/qmenubarimpl_p.h @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QMENUBARIMPL_P_H +#define QMENUBARIMPL_P_H + +#ifndef QT_NO_MENUBAR + +#include "qabstractmenubarimpl_p.h" + +QT_BEGIN_NAMESPACE + +class QMenuBar; + +class QMenuBarImpl : public QAbstractMenuBarImpl +{ +public: + ~QMenuBarImpl(); + + virtual void init(QMenuBar *); + + virtual bool allowSetVisible() const; + + virtual void actionEvent(QActionEvent *e); + + virtual void handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow); + + virtual bool allowCornerWidgets() const; + + virtual void popupAction(QAction*); + + virtual void setNativeMenuBar(bool); + virtual bool isNativeMenuBar() const; + + virtual bool shortcutsHandledByNativeMenuBar() const; + virtual bool menuBarEventFilter(QObject *, QEvent *event); + +private: + QMenuBar *menuBar; + int nativeMenuBar : 3; // Only has values -1, 0, and 1 + +#ifdef Q_WS_MAC + //mac menubar binding + struct QMacMenuBarPrivate { + QList actionItems; + OSMenuRef menu, apple_menu; + QMacMenuBarPrivate(); + ~QMacMenuBarPrivate(); + + void addAction(QAction *, QAction* =0); + void addAction(QMacMenuAction *, QMacMenuAction* =0); + void syncAction(QMacMenuAction *); + inline void syncAction(QAction *a) { syncAction(findAction(a)); } + void removeAction(QMacMenuAction *); + inline void removeAction(QAction *a) { removeAction(findAction(a)); } + inline QMacMenuAction *findAction(QAction *a) { + for(int i = 0; i < actionItems.size(); i++) { + QMacMenuAction *act = actionItems[i]; + if(a == act->action) + return act; + } + return 0; + } + } adapter; + static bool macUpdateMenuBarImmediatly(); + bool macWidgetHasNativeMenubar(QWidget *widget); + void macCreateMenuBar(QWidget *); + void macDestroyMenuBar(); + OSMenuRef macMenu(); +#endif +#ifdef Q_WS_WINCE + void wceCreateMenuBar(QWidget *); + void wceDestroyMenuBar(); + struct QWceMenuBarPrivate { + QList actionItems; + QList actionItemsLeftButton; + QList> actionItemsClassic; + HMENU menuHandle; + HMENU leftButtonMenuHandle; + HWND menubarHandle; + HWND parentWindowHandle; + bool leftButtonIsMenu; + QPointer leftButtonAction; + QMenuBarPrivate *d; + int leftButtonCommand; + + QWceMenuBarPrivate(QMenuBarPrivate *menubar); + ~QWceMenuBarPrivate(); + void addAction(QAction *, QAction* =0); + void addAction(QWceMenuAction *, QWceMenuAction* =0); + void syncAction(QWceMenuAction *); + inline void syncAction(QAction *a) { syncAction(findAction(a)); } + void removeAction(QWceMenuAction *); + void rebuild(); + inline void removeAction(QAction *a) { removeAction(findAction(a)); } + inline QWceMenuAction *findAction(QAction *a) { + for(int i = 0; i < actionItems.size(); i++) { + QWceMenuAction *act = actionItems[i]; + if(a == act->action) + return act; + } + return 0; + } + } adapter; + bool wceClassicMenu; + void wceCommands(uint command); + void wceRefresh(); + bool wceEmitSignals(QList actions, uint command); +#endif +#ifdef Q_WS_S60 + void symbianCreateMenuBar(QWidget *); + void symbianDestroyMenuBar(); + void reparentMenuBar(QWidget *oldParent, QWidget *newParent); + struct QSymbianMenuBarPrivate { + QList actionItems; + QMenuBarPrivate *d; + QSymbianMenuBarPrivate(QMenuBarPrivate *menubar); + ~QSymbianMenuBarPrivate(); + void addAction(QAction *, QAction* =0); + void addAction(QSymbianMenuAction *, QSymbianMenuAction* =0); + void syncAction(QSymbianMenuAction *); + inline void syncAction(QAction *a) { syncAction(findAction(a)); } + void removeAction(QSymbianMenuAction *); + void rebuild(); + inline void removeAction(QAction *a) { removeAction(findAction(a)); } + inline QSymbianMenuAction *findAction(QAction *a) { + for(int i = 0; i < actionItems.size(); i++) { + QSymbianMenuAction *act = actionItems[i]; + if(a == act->action) + return act; + } + return 0; + } + void insertNativeMenuItems(const QList &actions); + + } adapter; + static int symbianCommands(int command); +#endif +}; + +QT_END_NAMESPACE + +#endif // QT_NO_MENUBAR + +#endif /* QMENUBARIMPL_P_H */ diff --git a/src/gui/widgets/widgets.pri b/src/gui/widgets/widgets.pri index 669b838..e5d6890 100644 --- a/src/gui/widgets/widgets.pri +++ b/src/gui/widgets/widgets.pri @@ -4,6 +4,7 @@ HEADERS += \ widgets/qbuttongroup.h \ widgets/qabstractbutton.h \ widgets/qabstractbutton_p.h \ + widgets/qabstractmenubarimpl_p.h \ widgets/qabstractslider.h \ widgets/qabstractslider_p.h \ widgets/qabstractspinbox.h \ @@ -84,6 +85,7 @@ HEADERS += \ widgets/qprintpreviewwidget.h SOURCES += \ widgets/qabstractbutton.cpp \ + widgets/qabstractmenubarimpl_p.cpp \ widgets/qabstractslider.cpp \ widgets/qabstractspinbox.cpp \ widgets/qcalendarwidget.cpp \ @@ -110,6 +112,7 @@ SOURCES += \ widgets/qmdisubwindow.cpp \ widgets/qmenu.cpp \ widgets/qmenubar.cpp \ + widgets/qmenubarimpl.cpp \ widgets/qmenudata.cpp \ widgets/qprogressbar.cpp \ widgets/qpushbutton.cpp \ -- cgit v0.12 From be0d346052d69693c2780e62401f3c0d4b0d89d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20G=C3=A2teau?= Date: Thu, 14 Apr 2011 10:00:27 +0200 Subject: Introduce menubar plugin system Merge-request: 916 Reviewed-by: Thierry Bastian --- src/gui/widgets/qabstractmenubarimpl_p.h | 12 ++++++++++++ src/gui/widgets/qmenubar.cpp | 4 +++- src/gui/widgets/qmenubarimpl.cpp | 24 ++++++++++++++++++++++++ src/gui/widgets/qmenubarimpl_p.h | 2 ++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/qabstractmenubarimpl_p.h b/src/gui/widgets/qabstractmenubarimpl_p.h index d001008..76eef28 100644 --- a/src/gui/widgets/qabstractmenubarimpl_p.h +++ b/src/gui/widgets/qabstractmenubarimpl_p.h @@ -41,7 +41,9 @@ #ifndef QABSTRACTMENUBARIMPL_P_H #define QABSTRACTMENUBARIMPL_P_H +#include #include +#include #ifndef QT_NO_MENUBAR @@ -54,6 +56,16 @@ class QMenuBar; class QObject; class QWidget; +class QAbstractMenuBarImpl; + +struct QMenuBarImplFactoryInterface : public QFactoryInterface +{ + virtual QAbstractMenuBarImpl* createImpl() = 0; +}; + +#define QMenuBarImplFactoryInterface_iid "com.nokia.qt.QMenuBarImplFactoryInterface" +Q_DECLARE_INTERFACE(QMenuBarImplFactoryInterface, QMenuBarImplFactoryInterface_iid) + /** * The platform-specific implementation of a menubar */ diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index 0d13574..ec19908 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #ifndef QT_NO_MENUBAR @@ -728,7 +729,8 @@ void QMenuBarPrivate::init() Q_Q(QMenuBar); q->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); q->setAttribute(Qt::WA_CustomWhatsThis); - impl = new QMenuBarImpl; + + impl = qt_guiMenuBarImplFactory()->createImpl(); impl->init(q); q->setBackgroundRole(QPalette::Button); diff --git a/src/gui/widgets/qmenubarimpl.cpp b/src/gui/widgets/qmenubarimpl.cpp index 195f0ea..4844e4e 100644 --- a/src/gui/widgets/qmenubarimpl.cpp +++ b/src/gui/widgets/qmenubarimpl.cpp @@ -48,6 +48,8 @@ #include "qmenu.h" #include "qmenubar.h" +#include + QT_BEGIN_NAMESPACE QMenuBarImpl::~QMenuBarImpl() @@ -239,6 +241,28 @@ bool QMenuBarImpl::menuBarEventFilter(QObject *, QEvent *) return false; } +struct QMenuBarImplFactory : public QMenuBarImplFactoryInterface +{ + QAbstractMenuBarImpl* createImpl() { return new QMenuBarImpl; } + virtual QStringList keys() const { return QStringList(); } +}; + +QMenuBarImplFactoryInterface *qt_guiMenuBarImplFactory() +{ + static QMenuBarImplFactoryInterface *factory = 0; + if (!factory) { +#ifndef QT_NO_LIBRARY + QFactoryLoader loader(QMenuBarImplFactoryInterface_iid, QLatin1String("/menubar")); + factory = qobject_cast(loader.instance(QLatin1String("default"))); +#endif // QT_NO_LIBRARY + if(!factory) { + static QMenuBarImplFactory def; + factory = &def; + } + } + return factory; +} + QT_END_NAMESPACE #endif // QT_NO_MENUBAR diff --git a/src/gui/widgets/qmenubarimpl_p.h b/src/gui/widgets/qmenubarimpl_p.h index e770b5b..0546eb2 100644 --- a/src/gui/widgets/qmenubarimpl_p.h +++ b/src/gui/widgets/qmenubarimpl_p.h @@ -175,6 +175,8 @@ private: #endif }; +QMenuBarImplFactoryInterface *qt_guiMenuBarImplFactory(); + QT_END_NAMESPACE #endif // QT_NO_MENUBAR -- cgit v0.12 From bafeffd7b8b2c40761369ba496ee655dff6cf2a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20G=C3=A2teau?= Date: Thu, 14 Apr 2011 10:00:30 +0200 Subject: QAbstractMenuBarImpl::allowSetVisible => setVisible This makes it possible to alter the behavior of QMenuBar::setVisible(). It seems to be needed for the Mac menubar. Merge-request: 916 Reviewed-by: Thierry Bastian --- src/gui/widgets/qabstractmenubarimpl_p.h | 3 +-- src/gui/widgets/qmenubar.cpp | 5 +---- src/gui/widgets/qmenubarimpl.cpp | 10 +++------- src/gui/widgets/qmenubarimpl_p.h | 2 +- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/gui/widgets/qabstractmenubarimpl_p.h b/src/gui/widgets/qabstractmenubarimpl_p.h index 76eef28..25441df 100644 --- a/src/gui/widgets/qabstractmenubarimpl_p.h +++ b/src/gui/widgets/qabstractmenubarimpl_p.h @@ -77,8 +77,7 @@ public: // QMenuBarPrivate::init() virtual void init(QMenuBar *) = 0; - // QMenuBar::setVisible() - virtual bool allowSetVisible() const = 0; + virtual void setVisible(bool visible) = 0; virtual void actionEvent(QActionEvent *) = 0; diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index ec19908..556c192 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -1055,10 +1055,7 @@ void QMenuBar::paintEvent(QPaintEvent *e) void QMenuBar::setVisible(bool visible) { Q_D(QMenuBar); - if (!d->impl->allowSetVisible()) { - return; - } - QWidget::setVisible(visible); + d->impl->setVisible(visible); } /*! diff --git a/src/gui/widgets/qmenubarimpl.cpp b/src/gui/widgets/qmenubarimpl.cpp index 4844e4e..1ca2e11 100644 --- a/src/gui/widgets/qmenubarimpl.cpp +++ b/src/gui/widgets/qmenubarimpl.cpp @@ -90,20 +90,16 @@ void QMenuBarImpl::init(QMenuBar *_menuBar) #endif } -bool QMenuBarImpl::allowSetVisible() const +void QMenuBarImpl::setVisible(bool visible) { #if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) - // FIXME: Port this to a setVisible() method - /* if (isNativeMenuBar()) { if (!visible) - QWidget::setVisible(false); + menuBar->QWidget::setVisible(false); return; } - */ - return !isNativeMenuBar(); #endif - return true; + menuBar->QWidget::setVisible(visible); } void QMenuBarImpl::actionEvent(QActionEvent *e) diff --git a/src/gui/widgets/qmenubarimpl_p.h b/src/gui/widgets/qmenubarimpl_p.h index 0546eb2..e7a3bde 100644 --- a/src/gui/widgets/qmenubarimpl_p.h +++ b/src/gui/widgets/qmenubarimpl_p.h @@ -56,7 +56,7 @@ public: virtual void init(QMenuBar *); - virtual bool allowSetVisible() const; + virtual void setVisible(bool visible); virtual void actionEvent(QActionEvent *e); -- cgit v0.12 From a624a4011adca00d7334462c4d33f574c465110a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20G=C3=A2teau?= Date: Thu, 14 Apr 2011 10:00:33 +0200 Subject: Make ctor and dtor of QAbstractMenuBarImpl inline This way the class does not need to be exported Merge-request: 916 Reviewed-by: Thierry Bastian --- src/gui/widgets/qabstractmenubarimpl_p.cpp | 44 ------------------------------ src/gui/widgets/qabstractmenubarimpl_p.h | 5 ++-- src/gui/widgets/widgets.pri | 1 - 3 files changed, 3 insertions(+), 47 deletions(-) delete mode 100644 src/gui/widgets/qabstractmenubarimpl_p.cpp diff --git a/src/gui/widgets/qabstractmenubarimpl_p.cpp b/src/gui/widgets/qabstractmenubarimpl_p.cpp deleted file mode 100644 index bc16030..0000000 --- a/src/gui/widgets/qabstractmenubarimpl_p.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include - -QAbstractMenuBarImpl::~QAbstractMenuBarImpl() -{} diff --git a/src/gui/widgets/qabstractmenubarimpl_p.h b/src/gui/widgets/qabstractmenubarimpl_p.h index 25441df..156ee6a 100644 --- a/src/gui/widgets/qabstractmenubarimpl_p.h +++ b/src/gui/widgets/qabstractmenubarimpl_p.h @@ -69,10 +69,11 @@ Q_DECLARE_INTERFACE(QMenuBarImplFactoryInterface, QMenuBarImplFactoryInterface_i /** * The platform-specific implementation of a menubar */ -class Q_GUI_EXPORT QAbstractMenuBarImpl +class QAbstractMenuBarImpl { public: - virtual ~QAbstractMenuBarImpl(); + QAbstractMenuBarImpl() {} + virtual ~QAbstractMenuBarImpl() {} // QMenuBarPrivate::init() virtual void init(QMenuBar *) = 0; diff --git a/src/gui/widgets/widgets.pri b/src/gui/widgets/widgets.pri index e5d6890..f39b941 100644 --- a/src/gui/widgets/widgets.pri +++ b/src/gui/widgets/widgets.pri @@ -85,7 +85,6 @@ HEADERS += \ widgets/qprintpreviewwidget.h SOURCES += \ widgets/qabstractbutton.cpp \ - widgets/qabstractmenubarimpl_p.cpp \ widgets/qabstractslider.cpp \ widgets/qabstractspinbox.cpp \ widgets/qcalendarwidget.cpp \ -- cgit v0.12 From 3d188ffae259584c4351c5fa766a49da9b189112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20G=C3=A2teau?= Date: Thu, 14 Apr 2011 10:00:36 +0200 Subject: Renamed QAbstractMenuBarImpl to QAbstractMenuBarInterface Merge-request: 916 Reviewed-by: Thierry Bastian --- src/gui/widgets/qabstractmenubarimpl_p.h | 116 -------------------------- src/gui/widgets/qabstractmenubarinterface_p.h | 116 ++++++++++++++++++++++++++ src/gui/widgets/qmenubar_p.h | 4 +- src/gui/widgets/qmenubarimpl.cpp | 2 +- src/gui/widgets/qmenubarimpl_p.h | 4 +- src/gui/widgets/widgets.pri | 2 +- 6 files changed, 122 insertions(+), 122 deletions(-) delete mode 100644 src/gui/widgets/qabstractmenubarimpl_p.h create mode 100644 src/gui/widgets/qabstractmenubarinterface_p.h diff --git a/src/gui/widgets/qabstractmenubarimpl_p.h b/src/gui/widgets/qabstractmenubarimpl_p.h deleted file mode 100644 index 156ee6a..0000000 --- a/src/gui/widgets/qabstractmenubarimpl_p.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QABSTRACTMENUBARIMPL_P_H -#define QABSTRACTMENUBARIMPL_P_H - -#include -#include -#include - -#ifndef QT_NO_MENUBAR - -QT_BEGIN_NAMESPACE - -class QAction; -class QActionEvent; -class QEvent; -class QMenuBar; -class QObject; -class QWidget; - -class QAbstractMenuBarImpl; - -struct QMenuBarImplFactoryInterface : public QFactoryInterface -{ - virtual QAbstractMenuBarImpl* createImpl() = 0; -}; - -#define QMenuBarImplFactoryInterface_iid "com.nokia.qt.QMenuBarImplFactoryInterface" -Q_DECLARE_INTERFACE(QMenuBarImplFactoryInterface, QMenuBarImplFactoryInterface_iid) - -/** - * The platform-specific implementation of a menubar - */ -class QAbstractMenuBarImpl -{ -public: - QAbstractMenuBarImpl() {} - virtual ~QAbstractMenuBarImpl() {} - - // QMenuBarPrivate::init() - virtual void init(QMenuBar *) = 0; - - virtual void setVisible(bool visible) = 0; - - virtual void actionEvent(QActionEvent *) = 0; - - // QMenuBar::handleReparent() - virtual void handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow) = 0; - - // QMenuBarPrivate::updateGeometries() - // QMenuBar::minimumSizeHint() - // QMenuBar::sizeHint() - // QMenuBar::heightForWidth() - virtual bool allowCornerWidgets() const = 0; - - // QMenuBar::_q_internalShortcutActivated() - virtual void popupAction(QAction*) = 0; - - // QMenuBar::setNativeMenuBar() - virtual void setNativeMenuBar(bool) = 0; - - virtual bool isNativeMenuBar() const = 0; - - /** - * Return true if the native menubar is capable of listening to the - * shortcut keys. If false is returned, QMenuBar will trigger actions on - * shortcut itself. - */ - virtual bool shortcutsHandledByNativeMenuBar() const = 0; - - virtual bool menuBarEventFilter(QObject *, QEvent *event) = 0; -}; - -QT_END_NAMESPACE - -#endif // QT_NO_MENUBAR - -#endif // QABSTRACTMENUBARIMPL_P_H diff --git a/src/gui/widgets/qabstractmenubarinterface_p.h b/src/gui/widgets/qabstractmenubarinterface_p.h new file mode 100644 index 0000000..a014bc1 --- /dev/null +++ b/src/gui/widgets/qabstractmenubarinterface_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QABSTRACTMENUBARINTERFACE_P_H +#define QABSTRACTMENUBARINTERFACE_P_H + +#include +#include +#include + +#ifndef QT_NO_MENUBAR + +QT_BEGIN_NAMESPACE + +class QAction; +class QActionEvent; +class QEvent; +class QMenuBar; +class QObject; +class QWidget; + +class QAbstractMenuBarInterface; + +struct QMenuBarImplFactoryInterface : public QFactoryInterface +{ + virtual QAbstractMenuBarInterface* createImpl() = 0; +}; + +#define QMenuBarImplFactoryInterface_iid "com.nokia.qt.QMenuBarImplFactoryInterface" +Q_DECLARE_INTERFACE(QMenuBarImplFactoryInterface, QMenuBarImplFactoryInterface_iid) + +/** + * The platform-specific implementation of a menubar + */ +class QAbstractMenuBarInterface +{ +public: + QAbstractMenuBarInterface() {} + virtual ~QAbstractMenuBarInterface() {} + + // QMenuBarPrivate::init() + virtual void init(QMenuBar *) = 0; + + virtual void setVisible(bool visible) = 0; + + virtual void actionEvent(QActionEvent *) = 0; + + // QMenuBar::handleReparent() + virtual void handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow) = 0; + + // QMenuBarPrivate::updateGeometries() + // QMenuBar::minimumSizeHint() + // QMenuBar::sizeHint() + // QMenuBar::heightForWidth() + virtual bool allowCornerWidgets() const = 0; + + // QMenuBar::_q_internalShortcutActivated() + virtual void popupAction(QAction*) = 0; + + // QMenuBar::setNativeMenuBar() + virtual void setNativeMenuBar(bool) = 0; + + virtual bool isNativeMenuBar() const = 0; + + /** + * Return true if the native menubar is capable of listening to the + * shortcut keys. If false is returned, QMenuBar will trigger actions on + * shortcut itself. + */ + virtual bool shortcutsHandledByNativeMenuBar() const = 0; + + virtual bool menuBarEventFilter(QObject *, QEvent *event) = 0; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_MENUBAR + +#endif // QABSTRACTMENUBARINTERFACE_P_H diff --git a/src/gui/widgets/qmenubar_p.h b/src/gui/widgets/qmenubar_p.h index b49e039..427cd30 100644 --- a/src/gui/widgets/qmenubar_p.h +++ b/src/gui/widgets/qmenubar_p.h @@ -61,7 +61,7 @@ #include "qguifunctions_wince.h" #endif -#include "qabstractmenubarimpl_p.h" +#include "qabstractmenubarinterface_p.h" #ifndef QT_NO_MENUBAR #ifdef Q_WS_S60 @@ -160,7 +160,7 @@ public: #ifdef QT3_SUPPORT bool doAutoResize; #endif - QAbstractMenuBarImpl *impl; + QAbstractMenuBarInterface *impl; #ifdef QT_SOFTKEYS_ENABLED QAction *menuBarAction; #endif diff --git a/src/gui/widgets/qmenubarimpl.cpp b/src/gui/widgets/qmenubarimpl.cpp index 1ca2e11..4f2ad72 100644 --- a/src/gui/widgets/qmenubarimpl.cpp +++ b/src/gui/widgets/qmenubarimpl.cpp @@ -239,7 +239,7 @@ bool QMenuBarImpl::menuBarEventFilter(QObject *, QEvent *) struct QMenuBarImplFactory : public QMenuBarImplFactoryInterface { - QAbstractMenuBarImpl* createImpl() { return new QMenuBarImpl; } + QAbstractMenuBarInterface* createImpl() { return new QMenuBarImpl; } virtual QStringList keys() const { return QStringList(); } }; diff --git a/src/gui/widgets/qmenubarimpl_p.h b/src/gui/widgets/qmenubarimpl_p.h index e7a3bde..08ac6a0 100644 --- a/src/gui/widgets/qmenubarimpl_p.h +++ b/src/gui/widgets/qmenubarimpl_p.h @@ -43,13 +43,13 @@ #ifndef QT_NO_MENUBAR -#include "qabstractmenubarimpl_p.h" +#include "qabstractmenubarinterface_p.h" QT_BEGIN_NAMESPACE class QMenuBar; -class QMenuBarImpl : public QAbstractMenuBarImpl +class QMenuBarImpl : public QAbstractMenuBarInterface { public: ~QMenuBarImpl(); diff --git a/src/gui/widgets/widgets.pri b/src/gui/widgets/widgets.pri index f39b941..97d23f7 100644 --- a/src/gui/widgets/widgets.pri +++ b/src/gui/widgets/widgets.pri @@ -4,7 +4,7 @@ HEADERS += \ widgets/qbuttongroup.h \ widgets/qabstractbutton.h \ widgets/qabstractbutton_p.h \ - widgets/qabstractmenubarimpl_p.h \ + widgets/qabstractmenubarinterface_p.h \ widgets/qabstractslider.h \ widgets/qabstractslider_p.h \ widgets/qabstractspinbox.h \ -- cgit v0.12 From 56c3de426d97ab7c8fbb3f5766e1872d6f2e91e9 Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Thu, 14 Apr 2011 11:26:34 +0200 Subject: Fix copyright and a few codestyle mistakes Reviewed-By: Trust-Me Merge-Request: 916 --- src/gui/widgets/qmenubar.cpp | 194 +++++++++++++++++++-------------------- src/gui/widgets/qmenubarimpl.cpp | 18 ++-- src/gui/widgets/qmenubarimpl_p.h | 15 +-- 3 files changed, 113 insertions(+), 114 deletions(-) diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index 556c192..357c0fa 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -122,8 +122,8 @@ QSize QMenuBarExtension::sizeHint() const */ QAction *QMenuBarPrivate::actionAt(QPoint p) const { - for(int i = 0; i < actions.size(); ++i) { - if(actionRect(actions.at(i)).contains(p)) + for (int i = 0; i < actions.size(); ++i) { + if (actionRect(actions.at(i)).contains(p)) return actions.at(i); } return 0; @@ -171,12 +171,12 @@ bool QMenuBarPrivate::isVisible(QAction *action) void QMenuBarPrivate::updateGeometries() { Q_Q(QMenuBar); - if(!itemsDirty) + if (!itemsDirty) return; int q_width = q->width()-(q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q)*2); int q_start = -1; - if(impl->allowCornerWidgets() && (leftWidget || rightWidget)) { + if (impl->allowCornerWidgets() && (leftWidget || rightWidget)) { int vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, q) + q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q); int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarHMargin, 0, q) @@ -199,7 +199,7 @@ void QMenuBarPrivate::updateGeometries() } #ifndef QT_NO_SHORTCUT - if(!impl->shortcutsHandledByNativeMenuBar() && itemsDirty) { + if (!impl->shortcutsHandledByNativeMenuBar() && itemsDirty) { for(int j = 0; j < shortcutIndexMap.size(); ++j) q->releaseShortcut(shortcutIndexMap.value(j)); shortcutIndexMap.resize(0); // faster than clear @@ -207,7 +207,7 @@ void QMenuBarPrivate::updateGeometries() shortcutIndexMap.append(q->grabShortcut(QKeySequence::mnemonic(actions.at(i)->text()))); } #endif - if(q->isNativeMenuBar()) {//nothing to see here folks, move along.. + if (q->isNativeMenuBar()) {//nothing to see here folks, move along.. itemsDirty = false; return; } @@ -282,7 +282,7 @@ QRect QMenuBarPrivate::actionRect(QAction *act) const void QMenuBarPrivate::focusFirstAction() { - if(!currentAction) { + if (!currentAction) { updateGeometries(); int index = 0; while (index < actions.count() && actionRects.at(index).isNull()) ++index; @@ -299,16 +299,16 @@ void QMenuBarPrivate::setKeyboardMode(bool b) return; } keyboardState = b; - if(b) { + if (b) { QWidget *fw = QApplication::focusWidget(); if (fw != q) keyboardFocusWidget = fw; focusFirstAction(); q->setFocus(Qt::MenuBarFocusReason); } else { - if(!popupState) + if (!popupState) setCurrentAction(0); - if(keyboardFocusWidget) { + if (keyboardFocusWidget) { if (QApplication::focusWidget() == q) keyboardFocusWidget->setFocus(Qt::MenuBarFocusReason); keyboardFocusWidget = 0; @@ -320,7 +320,7 @@ void QMenuBarPrivate::setKeyboardMode(bool b) void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) { Q_Q(QMenuBar); - if(!action || !action->menu() || closePopupMode) + if (!action || !action->menu() || closePopupMode) return; popupState = true; if (action->isEnabled() && action->menu()->isEnabled()) { @@ -360,10 +360,10 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) pos.rx() += actionWidth; } - if(!defaultPopDown || (fitUp && !fitDown)) + if (!defaultPopDown || (fitUp && !fitDown)) pos.setY(qMax(screenRect.y(), q->mapToGlobal(QPoint(0, adjustedActionRect.top()-popup_size.height())).y())); activeMenu->popup(pos); - if(activateFirst) + if (activateFirst) activeMenu->d_func()->setFirstActionActive(); } q->update(actionRect(action)); @@ -371,7 +371,7 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activateFirst) { - if(currentAction == action && popup == popupState) + if (currentAction == action && popup == popupState) return; autoReleaseTimer.stop(); @@ -379,7 +379,7 @@ void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activat doChildEffects = (popup && !activeMenu); Q_Q(QMenuBar); QWidget *fw = 0; - if(QMenu *menu = activeMenu) { + if (QMenu *menu = activeMenu) { activeMenu = 0; if (popup) { fw = q->window()->focusWidget(); @@ -388,7 +388,7 @@ void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activat menu->hide(); } - if(currentAction) + if (currentAction) q->update(actionRect(currentAction)); popupState = popup; @@ -398,7 +398,7 @@ void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activat currentAction = action; if (action) { activateAction(action, QAction::Hover); - if(popup) + if (popup) popupAction(action, activateFirst); q->update(actionRect(action)); #ifndef QT_NO_STATUSTIP @@ -416,7 +416,7 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const { Q_Q(const QMenuBar); - if(!itemsDirty) + if (!itemsDirty) return; //let's reinitialize the buffer @@ -435,13 +435,13 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const icone = style->pixelMetric(QStyle::PM_SmallIconSize, 0, q); for(int i = 0; i < actions.count(); i++) { QAction *action = actions.at(i); - if(!action->isVisible()) + if (!action->isVisible()) continue; QSize sz; //calc what I think the size is.. - if(action->isSeparator()) { + i f(action->isSeparator()) { if (style->styleHint(QStyle::SH_DrawMenuBarSeparator, 0, q)) separator = i; continue; //we don't really position these! @@ -460,10 +460,10 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const q->initStyleOption(&opt, action); sz = q->style()->sizeFromContents(QStyle::CT_MenuBarItem, &opt, sz, q); - if(!sz.isEmpty()) { + if (!sz.isEmpty()) { { //update the separator state int iWidth = sz.width() + itemSpacing; - if(separator == -1) + if (separator == -1) separator_start += iWidth; else separator_len += iWidth; @@ -488,9 +488,9 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const rect.setHeight(max_item_height); //move - if(separator != -1 && i >= separator) { //after the separator + if (separator != -1 && i >= separator) { //after the separator int left = (max_width - separator_len - hmargin - itemSpacing) + (x - separator_start - hmargin); - if(left < separator_start) { //wrap + if (left < separator_start) { //wrap separator_start = x = hmargin; y += max_item_height; } @@ -517,9 +517,9 @@ void QMenuBarPrivate::activateAction(QAction *action, QAction::ActionEvent actio if (action_e == QAction::Hover) action->showStatusText(q); -// if(action_e == QAction::Trigger) +// if (action_e == QAction::Trigger) // emit q->activated(action); -// else if(action_e == QAction::Hover) +// else if (action_e == QAction::Hover) // emit q->highlighted(action); } @@ -1011,7 +1011,7 @@ void QMenuBar::paintEvent(QPaintEvent *e) QRect adjustedActionRect = d->actionRect(action); if (adjustedActionRect.isEmpty() || !d->isVisible(action)) continue; - if(!e->rect().intersects(adjustedActionRect)) + if (!e->rect().intersects(adjustedActionRect)) continue; emptyArea -= adjustedActionRect; @@ -1022,7 +1022,7 @@ void QMenuBar::paintEvent(QPaintEvent *e) style()->drawControl(QStyle::CE_MenuBarItem, &opt, &p, this); } //draw border - if(int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this)) { + if (int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this)) { QRegion borderReg; borderReg += QRect(0, 0, fw, height()); //left borderReg += QRect(width()-fw, 0, fw, height()); //right @@ -1064,7 +1064,7 @@ void QMenuBar::setVisible(bool visible) void QMenuBar::mousePressEvent(QMouseEvent *e) { Q_D(QMenuBar); - if(e->button() != Qt::LeftButton) + if (e->button() != Qt::LeftButton) return; d->mouseDown = true; @@ -1079,13 +1079,13 @@ void QMenuBar::mousePressEvent(QMouseEvent *e) return; } - if(d->currentAction == action && d->popupState) { - if(QMenu *menu = d->activeMenu) { + if (d->currentAction == action && d->popupState) { + if (QMenu *menu = d->activeMenu) { d->activeMenu = 0; menu->hide(); } #ifdef Q_WS_WIN - if((d->closePopupMode = style()->styleHint(QStyle::SH_MenuBar_DismissOnSecondClick))) + if ((d->closePopupMode = style()->styleHint(QStyle::SH_MenuBar_DismissOnSecondClick))) update(d->actionRect(action)); #endif } else { @@ -1099,16 +1099,16 @@ void QMenuBar::mousePressEvent(QMouseEvent *e) void QMenuBar::mouseReleaseEvent(QMouseEvent *e) { Q_D(QMenuBar); - if(e->button() != Qt::LeftButton || !d->mouseDown) + if (e->button() != Qt::LeftButton || !d->mouseDown) return; d->mouseDown = false; QAction *action = d->actionAt(e->pos()); - if((d->closePopupMode && action == d->currentAction) || !action || !action->menu()) { + if ((d->closePopupMode && action == d->currentAction) || !action || !action->menu()) { //we set the current action before activating //so that we let the leave event set the current back to 0 d->setCurrentAction(action, false); - if(action) + if (action) d->activateAction(action, QAction::Trigger); } d->closePopupMode = 0; @@ -1122,15 +1122,15 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) Q_D(QMenuBar); d->updateGeometries(); int key = e->key(); - if(isRightToLeft()) { // in reverse mode open/close key for submenues are reversed - if(key == Qt::Key_Left) + if (isRightToLeft()) { // in reverse mode open/close key for submenues are reversed + if (key == Qt::Key_Left) key = Qt::Key_Right; - else if(key == Qt::Key_Right) + else if (key == Qt::Key_Right) key = Qt::Key_Left; } - if(key == Qt::Key_Tab) //means right + if (key == Qt::Key_Tab) //means right key = Qt::Key_Right; - else if(key == Qt::Key_Backtab) //means left + else if (key == Qt::Key_Backtab) //means left key = Qt::Key_Left; bool key_consumed = false; @@ -1140,11 +1140,11 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) case Qt::Key_Enter: case Qt::Key_Space: case Qt::Key_Return: { - if(!style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, this) || !d->currentAction) + if (!style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, this) || !d->currentAction) break; - if(d->currentAction->menu()) { + if (d->currentAction->menu()) { d->popupAction(d->currentAction, true); - } else if(key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Space) { + } else if (key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Space) { d->activateAction(d->currentAction, QAction::Trigger); d->setCurrentAction(d->currentAction, false); d->setKeyboardMode(false); @@ -1154,7 +1154,7 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) case Qt::Key_Right: case Qt::Key_Left: { - if(d->currentAction) { + if (d->currentAction) { int index = d->actions.indexOf(d->currentAction); if (QAction *nextAction = d->getNextAction(index, key == Qt::Key_Left ? -1 : +1)) { d->setCurrentAction(nextAction, d->popupState, true); @@ -1173,7 +1173,7 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) key_consumed = false; } - if(!key_consumed && + if (!key_consumed && (!e->modifiers() || (e->modifiers()&(Qt::MetaModifier|Qt::AltModifier))) && e->text().length()==1 && !d->popupState) { int clashCount = 0; @@ -1185,14 +1185,14 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) continue; QAction *act = d->actions.at(i); QString s = act->text(); - if(!s.isEmpty()) { + if (!s.isEmpty()) { int ampersand = s.indexOf(QLatin1Char('&')); - if(ampersand >= 0) { - if(s[ampersand+1].toUpper() == c) { + if (ampersand >= 0) { + if (s[ampersand+1].toUpper() == c) { clashCount++; - if(!first) + if (!first) first = act; - if(act == d->currentAction) + if (act == d->currentAction) currentSelected = act; else if (!firstAfterCurrent && currentSelected) firstAfterCurrent = act; @@ -1202,18 +1202,18 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) } } QAction *next_action = 0; - if(clashCount >= 1) { - if(clashCount == 1 || !d->currentAction || (currentSelected && !firstAfterCurrent)) + if (clashCount >= 1) { + if (clashCount == 1 || !d->currentAction || (currentSelected && !firstAfterCurrent)) next_action = first; else next_action = firstAfterCurrent; } - if(next_action) { + if (next_action) { key_consumed = true; d->setCurrentAction(next_action, true, true); } } - if(key_consumed) + if (key_consumed) e->accept(); else e->ignore(); @@ -1239,7 +1239,7 @@ void QMenuBar::mouseMoveEvent(QMouseEvent *e) void QMenuBar::leaveEvent(QEvent *) { Q_D(QMenuBar); - if((!hasFocus() && !d->popupState) || + if ((!hasFocus() && !d->popupState) || (d->currentAction && d->currentAction->menu() == 0)) d->setCurrentAction(0); } @@ -1253,10 +1253,10 @@ void QMenuBar::actionEvent(QActionEvent *e) d->itemsDirty = true; d->impl->actionEvent(e); - if(e->type() == QEvent::ActionAdded) { + if (e->type() == QEvent::ActionAdded) { connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered())); connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered())); - } else if(e->type() == QEvent::ActionRemoved) { + } else if (e->type() == QEvent::ActionRemoved) { e->action()->disconnect(this); } if (isVisible()) { @@ -1271,7 +1271,7 @@ void QMenuBar::actionEvent(QActionEvent *e) void QMenuBar::focusInEvent(QFocusEvent *) { Q_D(QMenuBar); - if(d->keyboardState) + if (d->keyboardState) d->focusFirstAction(); } @@ -1281,7 +1281,7 @@ void QMenuBar::focusInEvent(QFocusEvent *) void QMenuBar::focusOutEvent(QFocusEvent *) { Q_D(QMenuBar); - if(!d->popupState) { + if (!d->popupState) { d->setCurrentAction(0); d->setKeyboardMode(false); } @@ -1371,10 +1371,10 @@ bool QMenuBar::autoGeometry() const void QMenuBar::changeEvent(QEvent *e) { Q_D(QMenuBar); - if(e->type() == QEvent::StyleChange) { + if (e->type() == QEvent::StyleChange) { d->itemsDirty = true; setMouseTracking(style()->styleHint(QStyle::SH_MenuBar_MouseTracking, 0, this)); - if(parentWidget()) + if (parentWidget()) resize(parentWidget()->width(), heightForWidth(parentWidget()->width())); d->updateGeometries(); } else if (e->type() == QEvent::ParentChange) { @@ -1403,12 +1403,12 @@ bool QMenuBar::event(QEvent *e) case QEvent::KeyPress: { QKeyEvent *ke = (QKeyEvent*)e; #if 0 - if(!d->keyboardState) { //all keypresses.. + if (!d->keyboardState) { //all keypresses.. d->setCurrentAction(0); return ; } #endif - if(ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) { + if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) { keyPressEvent(ke); return true; } @@ -1426,7 +1426,7 @@ bool QMenuBar::event(QEvent *e) #endif case QEvent::Show: #ifdef QT3_SUPPORT - if(QWidget *p = parentWidget()) { + if (QWidget *p = parentWidget()) { // If itemsDirty == true, updateGeometries sends the MenubarUpdated event. if (!d->itemsDirty) { QMenubarUpdatedEvent menubarUpdated(this); @@ -1448,7 +1448,7 @@ bool QMenuBar::event(QEvent *e) #ifdef QT3_SUPPORT case QEvent::Hide: { - if(QWidget *p = parentWidget()) { + if (QWidget *p = parentWidget()) { QMenubarUpdatedEvent menubarUpdated(this); QApplication::sendEvent(p, &menubarUpdated); } @@ -1584,7 +1584,7 @@ QSize QMenuBar::minimumSizeHint() const const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, this); int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this); int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, 0, this); - if(as_gui_menubar) { + if (as_gui_menubar) { int w = parentWidget() ? parentWidget()->width() : QApplication::desktop()->width(); d->calcActionRects(w - (2 * fw), 0); for (int i = 0; ret.isNull() && i < d->actions.count(); ++i) @@ -1595,20 +1595,20 @@ QSize QMenuBar::minimumSizeHint() const } int margin = 2*vmargin + 2*fw + spaceBelowMenuBar; if (d->impl->allowCornerWidgets()) { - if(d->leftWidget) { + if (d->leftWidget) { QSize sz = d->leftWidget->minimumSizeHint(); ret.setWidth(ret.width() + sz.width()); - if(sz.height() + margin > ret.height()) + if (sz.height() + margin > ret.height()) ret.setHeight(sz.height() + margin); } - if(d->rightWidget) { + if (d->rightWidget) { QSize sz = d->rightWidget->minimumSizeHint(); ret.setWidth(ret.width() + sz.width()); - if(sz.height() + margin > ret.height()) + if (sz.height() + margin > ret.height()) ret.setHeight(sz.height() + margin); } } - if(as_gui_menubar) { + if (as_gui_menubar) { QStyleOptionMenuItem opt; opt.rect = rect(); opt.menuRect = rect(); @@ -1638,7 +1638,7 @@ QSize QMenuBar::sizeHint() const const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, this); int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this); int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, 0, this); - if(as_gui_menubar) { + if (as_gui_menubar) { const int w = parentWidget() ? parentWidget()->width() : QApplication::desktop()->width(); d->calcActionRects(w - (2 * fw), 0); for (int i = 0; i < d->actionRects.count(); ++i) { @@ -1650,21 +1650,21 @@ QSize QMenuBar::sizeHint() const ret += QSize(fw + hmargin, fw + vmargin); } int margin = 2*vmargin + 2*fw + spaceBelowMenuBar; - if(d->impl->allowCornerWidgets()) { - if(d->leftWidget) { + if (d->impl->allowCornerWidgets()) { + if (d->leftWidget) { QSize sz = d->leftWidget->sizeHint(); ret.setWidth(ret.width() + sz.width()); - if(sz.height() + margin > ret.height()) + if (sz.height() + margin > ret.height()) ret.setHeight(sz.height() + margin); } - if(d->rightWidget) { + if (d->rightWidget) { QSize sz = d->rightWidget->sizeHint(); ret.setWidth(ret.width() + sz.width()); - if(sz.height() + margin > ret.height()) + if (sz.height() + margin > ret.height()) ret.setHeight(sz.height() + margin); } } - if(as_gui_menubar) { + if (as_gui_menubar) { QStyleOptionMenuItem opt; opt.rect = rect(); opt.menuRect = rect(); @@ -1692,7 +1692,7 @@ int QMenuBar::heightForWidth(int) const const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, this); int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this); int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, 0, this); - if(as_gui_menubar) { + if (as_gui_menubar) { for (int i = 0; i < d->actionRects.count(); ++i) height = qMax(height, d->actionRects.at(i).height()); if (height) //there is at least one non-null item @@ -1701,13 +1701,13 @@ int QMenuBar::heightForWidth(int) const height += 2*vmargin; } int margin = 2*vmargin + 2*fw + spaceBelowMenuBar; - if(d->impl->allowCornerWidgets()) { - if(d->leftWidget) + if (d->impl->allowCornerWidgets()) { + if (d->leftWidget) height = qMax(d->leftWidget->sizeHint().height() + margin, height); - if(d->rightWidget) + if (d->rightWidget) height = qMax(d->rightWidget->sizeHint().height() + margin, height); } - if(as_gui_menubar) { + if (as_gui_menubar) { QStyleOptionMenuItem opt; opt.init(this); opt.menuRect = rect(); @@ -1814,13 +1814,11 @@ void QMenuBar::setCornerWidget(QWidget *w, Qt::Corner corner) return; } - if(!d->impl->allowCornerWidgets()) { + if (!d->impl->allowCornerWidgets()) { d->updateCornerWidgetToolBar(); - } else { - if (w) { - w->setParent(this); - w->installEventFilter(this); - } + } else if (w) { + w->setParent(this); + w->installEventFilter(this); } d->_q_updateLayout(); @@ -1974,17 +1972,17 @@ int QMenuBar::insertAny(const QIcon *icon, const QString *text, const QObject *r const QKeySequence *shortcut, const QMenu *popup, int id, int index) { QAction *act = popup ? popup->menuAction() : new QAction(this); - if(id != -1) + if (id != -1) static_cast(act)->setId(id); - if(icon) + if (icon) act->setIcon(*icon); - if(text) + if (text) act->setText(*text); - if(shortcut) + if (shortcut) act->setShortcut(*shortcut); - if(receiver && member) + if (receiver && member) QObject::connect(act, SIGNAL(triggered(bool)), receiver, member); - if(index == -1 || index >= actions().count()) + if (index == -1 || index >= actions().count()) addAction(act); else insertAction(actions().value(index), act); @@ -2006,7 +2004,7 @@ int QMenuBar::insertSeparator(int index) { QAction *act = new QAction(this); act->setSeparator(true); - if(index == -1 || index >= actions().count()) + if (index == -1 || index >= actions().count()) addAction(act); else insertAction(actions().value(index), act); @@ -2018,7 +2016,7 @@ int QMenuBar::insertSeparator(int index) */ bool QMenuBar::setItemParameter(int id, int param) { - if(QAction *act = findActionForId(id)) { + if (QAction *act = findActionForId(id)) { act->d_func()->param = param; return true; } @@ -2030,7 +2028,7 @@ bool QMenuBar::setItemParameter(int id, int param) */ int QMenuBar::itemParameter(int id) const { - if(QAction *act = findActionForId(id)) + if (QAction *act = findActionForId(id)) return act->d_func()->param; return id; } diff --git a/src/gui/widgets/qmenubarimpl.cpp b/src/gui/widgets/qmenubarimpl.cpp index 4f2ad72..d402507 100644 --- a/src/gui/widgets/qmenubarimpl.cpp +++ b/src/gui/widgets/qmenubarimpl.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -38,6 +38,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + #include "qmenubarimpl_p.h" #ifndef QT_NO_MENUBAR @@ -75,16 +76,15 @@ void QMenuBarImpl::init(QMenuBar *_menuBar) #endif #ifdef Q_WS_MAC macCreateMenuBar(menuBar->parentWidget()); - if(adapter) + if (adapter) menuBar->hide(); #endif #ifdef Q_WS_WINCE if (qt_wince_is_mobile()) { wceCreateMenuBar(menuBar->parentWidget()); - if(adapter) + if (adapter) menuBar->hide(); - } - else { + } else { QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true); } #endif @@ -106,11 +106,11 @@ void QMenuBarImpl::actionEvent(QActionEvent *e) { #if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) if (adapter) { - if(e->type() == QEvent::ActionAdded) + if (e->type() == QEvent::ActionAdded) adapter->addAction(e->action(), e->before()); - else if(e->type() == QEvent::ActionRemoved) + else if (e->type() == QEvent::ActionRemoved) adapter->removeAction(e->action()); - else if(e->type() == QEvent::ActionChanged) + else if (e->type() == QEvent::ActionChanged) adapter->syncAction(e->action()); } #else @@ -251,7 +251,7 @@ QMenuBarImplFactoryInterface *qt_guiMenuBarImplFactory() QFactoryLoader loader(QMenuBarImplFactoryInterface_iid, QLatin1String("/menubar")); factory = qobject_cast(loader.instance(QLatin1String("default"))); #endif // QT_NO_LIBRARY - if(!factory) { + if (!factory) { static QMenuBarImplFactory def; factory = &def; } diff --git a/src/gui/widgets/qmenubarimpl_p.h b/src/gui/widgets/qmenubarimpl_p.h index 08ac6a0..749c395 100644 --- a/src/gui/widgets/qmenubarimpl_p.h +++ b/src/gui/widgets/qmenubarimpl_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -38,6 +38,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + #ifndef QMENUBARIMPL_P_H #define QMENUBARIMPL_P_H @@ -91,9 +92,9 @@ private: void removeAction(QMacMenuAction *); inline void removeAction(QAction *a) { removeAction(findAction(a)); } inline QMacMenuAction *findAction(QAction *a) { - for(int i = 0; i < actionItems.size(); i++) { + for (int i = 0; i < actionItems.size(); i++) { QMacMenuAction *act = actionItems[i]; - if(a == act->action) + if (a == act->action) return act; } return 0; @@ -131,9 +132,9 @@ private: void rebuild(); inline void removeAction(QAction *a) { removeAction(findAction(a)); } inline QWceMenuAction *findAction(QAction *a) { - for(int i = 0; i < actionItems.size(); i++) { + for (int i = 0; i < actionItems.size(); i++) { QWceMenuAction *act = actionItems[i]; - if(a == act->action) + if (a == act->action) return act; } return 0; @@ -161,9 +162,9 @@ private: void rebuild(); inline void removeAction(QAction *a) { removeAction(findAction(a)); } inline QSymbianMenuAction *findAction(QAction *a) { - for(int i = 0; i < actionItems.size(); i++) { + for (int i = 0; i < actionItems.size(); i++) { QSymbianMenuAction *act = actionItems[i]; - if(a == act->action) + if (a == act->action) return act; } return 0; -- cgit v0.12 From febdcef08f22310cbd70ec13b315f70ff8e41e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Tue, 15 Feb 2011 13:40:32 +0100 Subject: Do not call setSizePolicy from ctor, it might call a virtual function More specifically, it might very well call updateGeometry() Reviewed-by: Frederik Gladhorn --- src/gui/graphicsview/qgraphicslayout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/graphicsview/qgraphicslayout.cpp b/src/gui/graphicsview/qgraphicslayout.cpp index ed213f1..0ee1f06 100644 --- a/src/gui/graphicsview/qgraphicslayout.cpp +++ b/src/gui/graphicsview/qgraphicslayout.cpp @@ -167,7 +167,7 @@ QGraphicsLayout::QGraphicsLayout(QGraphicsLayoutItem *parent) " neither a QGraphicsWidget nor QGraphicsLayout"); } } - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, QSizePolicy::DefaultType); + d_func()->sizePolicy = QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, QSizePolicy::DefaultType); setOwnedByLayout(true); } @@ -188,7 +188,7 @@ QGraphicsLayout::QGraphicsLayout(QGraphicsLayoutPrivate &dd, QGraphicsLayoutItem " neither a QGraphicsWidget nor QGraphicsLayout"); } } - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, QSizePolicy::DefaultType); + d_func()->sizePolicy = QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, QSizePolicy::DefaultType); setOwnedByLayout(true); } -- cgit v0.12 From 42bbdbef501caec06981981585a0302339818ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Wed, 9 Feb 2011 15:07:24 +0100 Subject: Avoid flicker when invalidate is propagated in a widget/layout hierarchy * Do not call invalidate from activateRecursive(). This resulted in that a layout was invalidated as many times as there were items in the layout. * Several improvements. Do not call resize(size()) too often. Calling resize() from the widgetEvent() is not very nice though... * Remove commented out code * make sure layout is activated even if the widget does not change size * activate the layout if the resize is same as size() * In order to not break existing apps, make this an opt-in feature with QGraphicsLayout::setInstantInvalidatePropagation(true); Reviewed-by: Frederik Gladhorn Reviewed-by: John Tapsell --- src/gui/graphicsview/qgraphicslayout.cpp | 141 ++++++++++++++++----- src/gui/graphicsview/qgraphicslayout.h | 2 + src/gui/graphicsview/qgraphicslayout_p.cpp | 9 +- src/gui/graphicsview/qgraphicslinearlayout.cpp | 9 +- src/gui/graphicsview/qgraphicswidget.cpp | 105 ++++++++++----- .../tst_qgraphicsanchorlayout.cpp | 3 + tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp | 88 +++++++++++++ .../tst_qgraphicslinearlayout.cpp | 40 ++++++ 8 files changed, 321 insertions(+), 76 deletions(-) diff --git a/src/gui/graphicsview/qgraphicslayout.cpp b/src/gui/graphicsview/qgraphicslayout.cpp index 0ee1f06..e50989c 100644 --- a/src/gui/graphicsview/qgraphicslayout.cpp +++ b/src/gui/graphicsview/qgraphicslayout.cpp @@ -269,12 +269,20 @@ void QGraphicsLayout::activate() return; Q_ASSERT(!parentItem->isLayout()); - setGeometry(parentItem->contentsRect()); // relayout children - - // ### bug, should be parentItem ? - parentLayoutItem()->updateGeometry(); // bubble up; will set activated to false - // ### too many resizes? maybe we should walk up the chain to the - // ### top-level layouted layoutItem and call activate there. + if (QGraphicsLayout::instantInvalidatePropagation()) { + QGraphicsWidget *parentWidget = static_cast(parentItem); + if (!parentWidget->parentLayoutItem()) { + // we've reached the topmost widget, resize it + bool wasResized = parentWidget->testAttribute(Qt::WA_Resized); + parentWidget->resize(parentWidget->size()); + parentWidget->setAttribute(Qt::WA_Resized, wasResized); + } + + setGeometry(parentItem->contentsRect()); // relayout children + } else { + setGeometry(parentItem->contentsRect()); // relayout children + parentLayoutItem()->updateGeometry(); + } } /*! @@ -300,32 +308,36 @@ bool QGraphicsLayout::isActivated() const */ void QGraphicsLayout::invalidate() { - // only mark layouts as invalid (activated = false) if we can post a LayoutRequest event. - QGraphicsLayoutItem *layoutItem = this; - while (layoutItem && layoutItem->isLayout()) { - // we could call updateGeometry(), but what if that method - // does not call the base implementation? In addition, updateGeometry() - // does more than we need. - layoutItem->d_func()->sizeHintCacheDirty = true; - layoutItem->d_func()->sizeHintWithConstraintCacheDirty = true; - layoutItem = layoutItem->parentLayoutItem(); - } - if (layoutItem) { - layoutItem->d_func()->sizeHintCacheDirty = true; - layoutItem->d_func()->sizeHintWithConstraintCacheDirty = true; - } - - bool postIt = layoutItem ? !layoutItem->isLayout() : false; - if (postIt) { - layoutItem = this; - while (layoutItem && layoutItem->isLayout() - && static_cast(layoutItem)->d_func()->activated) { - static_cast(layoutItem)->d_func()->activated = false; + if (QGraphicsLayout::instantInvalidatePropagation()) { + updateGeometry(); + } else { + // only mark layouts as invalid (activated = false) if we can post a LayoutRequest event. + QGraphicsLayoutItem *layoutItem = this; + while (layoutItem && layoutItem->isLayout()) { + // we could call updateGeometry(), but what if that method + // does not call the base implementation? In addition, updateGeometry() + // does more than we need. + layoutItem->d_func()->sizeHintCacheDirty = true; + layoutItem->d_func()->sizeHintWithConstraintCacheDirty = true; layoutItem = layoutItem->parentLayoutItem(); } - if (layoutItem && !layoutItem->isLayout()) { - // If a layout has a parent that is not a layout it must be a QGraphicsWidget. - QApplication::postEvent(static_cast(layoutItem), new QEvent(QEvent::LayoutRequest)); + if (layoutItem) { + layoutItem->d_func()->sizeHintCacheDirty = true; + layoutItem->d_func()->sizeHintWithConstraintCacheDirty = true; + } + + bool postIt = layoutItem ? !layoutItem->isLayout() : false; + if (postIt) { + layoutItem = this; + while (layoutItem && layoutItem->isLayout() + && static_cast(layoutItem)->d_func()->activated) { + static_cast(layoutItem)->d_func()->activated = false; + layoutItem = layoutItem->parentLayoutItem(); + } + if (layoutItem && !layoutItem->isLayout()) { + // If a layout has a parent that is not a layout it must be a QGraphicsWidget. + QApplication::postEvent(static_cast(layoutItem), new QEvent(QEvent::LayoutRequest)); + } } } } @@ -335,12 +347,27 @@ void QGraphicsLayout::invalidate() */ void QGraphicsLayout::updateGeometry() { - QGraphicsLayoutItem::updateGeometry(); - if (QGraphicsLayoutItem *parentItem = parentLayoutItem()) { - if (parentItem->isLayout()) { + Q_D(QGraphicsLayout); + if (QGraphicsLayout::instantInvalidatePropagation()) { + d->activated = false; + QGraphicsLayoutItem::updateGeometry(); + + QGraphicsLayoutItem *parentItem = parentLayoutItem(); + if (!parentItem) + return; + + if (parentItem->isLayout()) + static_cast(parentItem)->invalidate(); + else parentItem->updateGeometry(); - } else { - invalidate(); + } else { + QGraphicsLayoutItem::updateGeometry(); + if (QGraphicsLayoutItem *parentItem = parentLayoutItem()) { + if (parentItem->isLayout()) { + parentItem->updateGeometry(); + } else { + invalidate(); + } } } } @@ -446,6 +473,50 @@ void QGraphicsLayout::addChildLayoutItem(QGraphicsLayoutItem *layoutItem) d->addChildLayoutItem(layoutItem); } +static bool g_instantInvalidatePropagation = false; + +/*! + \internal + \since 4.8 + \see instantInvalidatePropagation + + Calling this function with \a enable set to true will enable a feature that + makes propagation of invalidation up to ancestor layout items to be done in + one go. It will propagate up the parentLayoutItem() hierarchy until it has + reached the root. If the root item is a QGraphicsWidget, it will *post* a + layout request to it. When the layout request is consumed it will traverse + down the hierarchy of layouts and widgets and activate all layouts that is + invalid (not activated). This is the recommended behaviour. + + If not set it will also propagate up the parentLayoutItem() hierarchy, but + it will stop at the \i first \i widget it encounters, and post a layout + request to the widget. When the layout request is consumed, this might + cause it to continue propagation up to the parentLayoutItem() of the + widget. It will continue in this fashion until it has reached a widget with + no parentLayoutItem(). This strategy might cause drawing artifacts, since + it is not done in one go, and the consumption of layout requests might be + interleaved by consumption of paint events, which might cause significant + flicker. + Note, this is not the recommended behavior, but for compatibility reasons + this is the default behaviour. +*/ +void QGraphicsLayout::setInstantInvalidatePropagation(bool enable) +{ + g_instantInvalidatePropagation = enable; +} + +/*! + \internal + \since 4.8 + \see setInstantInvalidatePropagation + + returns true if the complete widget/layout hierarchy is rearranged in one go. +*/ +bool QGraphicsLayout::instantInvalidatePropagation() +{ + return g_instantInvalidatePropagation; +} + QT_END_NAMESPACE #endif //QT_NO_GRAPHICSVIEW diff --git a/src/gui/graphicsview/qgraphicslayout.h b/src/gui/graphicsview/qgraphicslayout.h index c622fb8..6031174 100644 --- a/src/gui/graphicsview/qgraphicslayout.h +++ b/src/gui/graphicsview/qgraphicslayout.h @@ -76,6 +76,8 @@ public: virtual QGraphicsLayoutItem *itemAt(int i) const = 0; virtual void removeAt(int index) = 0; + static void setInstantInvalidatePropagation(bool enable); + static bool instantInvalidatePropagation(); protected: QGraphicsLayout(QGraphicsLayoutPrivate &, QGraphicsLayoutItem *); void addChildLayoutItem(QGraphicsLayoutItem *layoutItem); diff --git a/src/gui/graphicsview/qgraphicslayout_p.cpp b/src/gui/graphicsview/qgraphicslayout_p.cpp index c2d4a08..6afdc19 100644 --- a/src/gui/graphicsview/qgraphicslayout_p.cpp +++ b/src/gui/graphicsview/qgraphicslayout_p.cpp @@ -180,8 +180,13 @@ void QGraphicsLayoutPrivate::activateRecursive(QGraphicsLayoutItem *item) { if (item->isLayout()) { QGraphicsLayout *layout = static_cast(item); - if (layout->d_func()->activated) - layout->invalidate(); + if (layout->d_func()->activated) { + if (QGraphicsLayout::instantInvalidatePropagation()) { + return; + } else { + layout->invalidate(); // ### LOOKS SUSPICIOUSLY WRONG!!??? + } + } for (int i = layout->count() - 1; i >= 0; --i) { QGraphicsLayoutItem *childItem = layout->itemAt(i); diff --git a/src/gui/graphicsview/qgraphicslinearlayout.cpp b/src/gui/graphicsview/qgraphicslinearlayout.cpp index 5591638..1229379 100644 --- a/src/gui/graphicsview/qgraphicslinearlayout.cpp +++ b/src/gui/graphicsview/qgraphicslinearlayout.cpp @@ -275,17 +275,16 @@ void QGraphicsLinearLayout::insertItem(int index, QGraphicsLayoutItem *item) qWarning("QGraphicsLinearLayout::insertItem: cannot insert itself"); return; } - Q_ASSERT(item); - //the order of the following instructions is very important because - //invalidating the layout before adding the child item will make the layout happen - //before we try to paint the item - invalidate(); d->addChildLayoutItem(item); d->fixIndex(&index); d->engine.insertRow(index, d->orientation); new QGridLayoutItem(&d->engine, item, d->gridRow(index), d->gridColumn(index), 1, 1, 0, index); + //the order of the following instructions is very important because + //invalidating the layout before adding the child item will make the layout happen + //before we try to paint the item + invalidate(); } /*! diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 675a5c5..141e305 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -354,8 +354,10 @@ void QGraphicsWidget::setGeometry(const QRectF &rect) newGeom = rect; newGeom.setSize(rect.size().expandedTo(effectiveSizeHint(Qt::MinimumSize)) .boundedTo(effectiveSizeHint(Qt::MaximumSize))); - if (newGeom == d->geom) - return; + + if (newGeom == d->geom) { + goto relayoutChildrenAndReturn; + } // setPos triggers ItemPositionChange, which can adjust position wd->inSetGeometry = 1; @@ -363,8 +365,9 @@ void QGraphicsWidget::setGeometry(const QRectF &rect) wd->inSetGeometry = 0; newGeom.moveTopLeft(pos()); - if (newGeom == d->geom) - return; + if (newGeom == d->geom) { + goto relayoutChildrenAndReturn; + } // Update and prepare to change the geometry (remove from index) if the size has changed. if (wd->scene) { @@ -375,35 +378,54 @@ void QGraphicsWidget::setGeometry(const QRectF &rect) } // Update the layout item geometry - bool moved = oldPos != pos(); - if (moved) { - // Send move event. - QGraphicsSceneMoveEvent event; - event.setOldPos(oldPos); - event.setNewPos(pos()); - QApplication::sendEvent(this, &event); - if (wd->inSetPos) { - //set the new pos - d->geom.moveTopLeft(pos()); - emit geometryChanged(); - return; + { + bool moved = oldPos != pos(); + if (moved) { + // Send move event. + QGraphicsSceneMoveEvent event; + event.setOldPos(oldPos); + event.setNewPos(pos()); + QApplication::sendEvent(this, &event); + if (wd->inSetPos) { + //set the new pos + d->geom.moveTopLeft(pos()); + emit geometryChanged(); + goto relayoutChildrenAndReturn; + } + } + QSizeF oldSize = size(); + QGraphicsLayoutItem::setGeometry(newGeom); + // Send resize event + bool resized = newGeom.size() != oldSize; + if (resized) { + QGraphicsSceneResizeEvent re; + re.setOldSize(oldSize); + re.setNewSize(newGeom.size()); + if (oldSize.width() != newGeom.size().width()) + emit widthChanged(); + if (oldSize.height() != newGeom.size().height()) + emit heightChanged(); + QGraphicsLayout *lay = wd->layout; + if (QGraphicsLayout::instantInvalidatePropagation()) { + if (!lay || lay->isActivated()) { + QApplication::sendEvent(this, &re); + } + } else { + QApplication::sendEvent(this, &re); + } } } - QSizeF oldSize = size(); - QGraphicsLayoutItem::setGeometry(newGeom); - // Send resize event - bool resized = newGeom.size() != oldSize; - if (resized) { - QGraphicsSceneResizeEvent re; - re.setOldSize(oldSize); - re.setNewSize(newGeom.size()); - if (oldSize.width() != newGeom.size().width()) - emit widthChanged(); - if (oldSize.height() != newGeom.size().height()) - emit heightChanged(); - QApplication::sendEvent(this, &re); - } + emit geometryChanged(); +relayoutChildrenAndReturn: + if (QGraphicsLayout::instantInvalidatePropagation()) { + if (QGraphicsLayout *lay = wd->layout) { + if (!lay->isActivated()) { + QEvent layoutRequest(QEvent::LayoutRequest); + QApplication::sendEvent(this, &layoutRequest); + } + } + } } /*! @@ -1052,16 +1074,31 @@ void QGraphicsWidget::updateGeometry() QGraphicsLayoutItem *parentItem = parentLayoutItem(); if (parentItem && parentItem->isLayout()) { - parentItem->updateGeometry(); + if (QGraphicsLayout::instantInvalidatePropagation()) { + static_cast(parentItem)->invalidate(); + } else { + parentItem->updateGeometry(); + } } else { if (parentItem) { + // This is for custom layouting QGraphicsWidget *parentWid = parentWidget(); //### if (parentWid->isVisible()) QApplication::postEvent(parentWid, new QEvent(QEvent::LayoutRequest)); + } else { + /** + * If this is the topmost widget, post a LayoutRequest event to the widget. + * When the event is received, it will start flowing all the way down to the leaf + * widgets in one go. This will make a relayout flicker-free. + */ + if (QGraphicsLayout::instantInvalidatePropagation()) + QApplication::postEvent(static_cast(this), new QEvent(QEvent::LayoutRequest)); + } + if (!QGraphicsLayout::instantInvalidatePropagation()) { + bool wasResized = testAttribute(Qt::WA_Resized); + resize(size()); // this will restrict the size + setAttribute(Qt::WA_Resized, wasResized); } - bool wasResized = testAttribute(Qt::WA_Resized); - resize(size()); // this will restrict the size - setAttribute(Qt::WA_Resized, wasResized); } } diff --git a/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp b/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp index e7c63d5..447385a 100644 --- a/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp +++ b/tests/auto/qgraphicsanchorlayout/tst_qgraphicsanchorlayout.cpp @@ -1091,6 +1091,9 @@ void tst_QGraphicsAnchorLayout::setSpacing() #ifdef Q_WS_MAC QTest::qWait(200); #endif + + // 21x21 + QCOMPARE(p->size(), QSizeF(41, 41)); QCOMPARE(a->geometry(), QRectF(0, 0, 20, 20)); QCOMPARE(b->geometry(), QRectF(21, 0, 20, 20)); QCOMPARE(c->geometry(), QRectF(0, 21, 41, 20)); diff --git a/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp b/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp index 979f03d..c57392640 100644 --- a/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp +++ b/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp @@ -62,6 +62,7 @@ private slots: void compressLayoutRequest(); void automaticReparenting(); void verifyActivate(); + void invalidate(); void constructors(); void alternativeLayoutItems(); void ownership(); @@ -218,6 +219,7 @@ class TestLayout : public QGraphicsLinearLayout : QGraphicsLinearLayout(parent) { m_count = 0; + m_invalidateCount = 0; } void setGeometry(const QRectF &rect) { @@ -226,7 +228,12 @@ class TestLayout : public QGraphicsLinearLayout QGraphicsLinearLayout::setGeometry(rect); } + void invalidate() { + ++m_invalidateCount; + QGraphicsLinearLayout::invalidate(); + } + int m_invalidateCount; int m_count; }; @@ -251,6 +258,87 @@ void tst_QGraphicsLayout::verifyActivate() } +void tst_QGraphicsLayout::invalidate() +{ + QGraphicsLayout::setInstantInvalidatePropagation(true); + QGraphicsScene scene; + QGraphicsView view(&scene); + + TestGraphicsWidget *a = new TestGraphicsWidget; + scene.addItem(a); + TestLayout *alay = new TestLayout(a); + TestGraphicsWidget *b = new TestGraphicsWidget; + alay->addItem(b); + TestLayout *blay = new TestLayout(b); + TestGraphicsWidget *e = new TestGraphicsWidget; + blay->addItem(e); + + + TestGraphicsWidget *c = new TestGraphicsWidget; + alay->addItem(c); + TestLayout *clay = new TestLayout(c); + TestGraphicsWidget *f = new TestGraphicsWidget; + clay->addItem(f); + + TestGraphicsWidget *d = new TestGraphicsWidget; + alay->addItem(d); + TestLayout *dlay = new TestLayout(d); + TestGraphicsWidget *g = new TestGraphicsWidget; + dlay->addItem(g); + + view.show(); + + alay->m_invalidateCount = 0; + blay->m_invalidateCount = 0; + clay->m_invalidateCount = 0; + dlay->m_invalidateCount = 0; + + QCoreApplication::sendPostedEvents(); + QCoreApplication::processEvents(); + + alay->activate(); + QCOMPARE(alay->isActivated(), true); + QCOMPARE(blay->isActivated(), true); + QCOMPARE(clay->isActivated(), true); + qDebug() << "alay->m_invalidateCount:" << alay->m_invalidateCount; + qDebug() << "blay->m_invalidateCount:" << blay->m_invalidateCount; + qDebug() << "clay->m_invalidateCount:" << clay->m_invalidateCount; + qDebug() << "dlay->m_invalidateCount:" << dlay->m_invalidateCount; + + a->clearEventCount(); + b->clearEventCount(); + c->clearEventCount(); + + blay->invalidate(); + QCOMPARE(alay->isActivated(), false); + QCOMPARE(blay->isActivated(), false); + QCOMPARE(clay->isActivated(), true); + QCOMPARE(a->eventCount(QEvent::LayoutRequest), 0); + QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); + QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); + + + alay->m_invalidateCount = 0; + blay->m_invalidateCount = 0; + clay->m_invalidateCount = 0; + dlay->m_invalidateCount = 0; + clay->invalidate(); + QCOMPARE(alay->isActivated(), false); + QCOMPARE(blay->isActivated(), false); + QCOMPARE(clay->isActivated(), false); + + QCoreApplication::sendPostedEvents(); + QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); + QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); + qDebug() << "alay->m_invalidateCount:" << alay->m_invalidateCount; + qDebug() << "blay->m_invalidateCount:" << blay->m_invalidateCount; + qDebug() << "clay->m_invalidateCount:" << clay->m_invalidateCount; + qDebug() << "dlay->m_invalidateCount:" << dlay->m_invalidateCount; + + QGraphicsLayout::setInstantInvalidatePropagation(false); +} + class Layout : public QGraphicsLayout { public: diff --git a/tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp b/tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp index 62ba1b4..8f8ac67 100644 --- a/tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp +++ b/tests/auto/qgraphicslinearlayout/tst_qgraphicslinearlayout.cpp @@ -94,6 +94,7 @@ private slots: void itemSpacing(); void setStretchFactor_data(); void setStretchFactor(); + void testStretch(); void defaultStretchFactors_data(); void defaultStretchFactors(); void sizeHint_data(); @@ -667,6 +668,10 @@ void tst_QGraphicsLinearLayout::invalidate() layout.setContentsMargins(0, 0, 0, 0); view.show(); widget->show(); + //QTest::qWait(1000); + QTest::qWaitForWindowShown(&view); + qApp->processEvents(); + layout.layoutRequest = 0; layout.setContentsMargins(1, 2, 3, 4); QApplication::sendPostedEvents(0, 0); @@ -1130,6 +1135,41 @@ void tst_QGraphicsLinearLayout::setStretchFactor() delete widget; } +void tst_QGraphicsLinearLayout::testStretch() +{ + QGraphicsScene scene; + QGraphicsView *view = new QGraphicsView(&scene); + QGraphicsWidget *form = new QGraphicsWidget(0, Qt::Window); + + scene.addItem(form); + form->setMinimumSize(600, 600); + form->setMaximumSize(600, 600); + QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Horizontal, form); + QGraphicsWidget *w1 = new RectWidget; + w1->setPreferredSize(100,100); + w1->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + QGraphicsWidget *w2 = new RectWidget; + w2->setPreferredSize(200,200); + w2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); + layout->addItem(w1); + layout->addStretch(2); + layout->addItem(w2); + QCOMPARE(layout->count(), 2); + QVERIFY(layout->itemAt(0) == w1); + QVERIFY(layout->itemAt(1) == w2); + layout->activate(); + + //view->setSceneRect(-50, -50, 800, 800); + //view->show(); + //QTest::qWaitForWindowShown(view); + //QTest::qWait(5000); + QCOMPARE(form->geometry().size(), QSizeF(600,600)); + QCOMPARE(w1->geometry(), QRectF(0, 0, 100, 100)); + QCOMPARE(w2->geometry(), QRectF(400, 0, 200, 200)); +} + void tst_QGraphicsLinearLayout::defaultStretchFactors_data() { QTest::addColumn("orientation"); -- cgit v0.12 From b8b4e6fe141d99c4639d492a546226cdc3fc06c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Fri, 18 Mar 2011 10:52:03 +0100 Subject: Improve invalidate() testcase. Test number of: * events * setGeometry() calls * invalidate() calls --- tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp | 335 +++++++++++++++++---- 1 file changed, 276 insertions(+), 59 deletions(-) diff --git a/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp b/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp index c57392640..29ea074 100644 --- a/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp +++ b/tests/auto/qgraphicslayout/tst_qgraphicslayout.cpp @@ -96,6 +96,14 @@ void tst_QGraphicsLayout::sizeHints() } +enum FunctionType { + SetGeometry = 0, + Invalidate, + NumFunctionTypes +}; + + + class TestGraphicsWidget : public QGraphicsWidget { public: TestGraphicsWidget(QGraphicsWidget *parent = 0) : QGraphicsWidget(parent) @@ -109,9 +117,28 @@ public: int eventCount(QEvent::Type type) { return m_eventCount.value(int(type)); } + void clearEventCount() { m_eventCount.clear(); } + + void clearCounters() { + m_eventCount.clear(); + functionCount.clear(); + } + + void setGeometry(const QRectF &rect) + { + QGraphicsWidget::setGeometry(rect); + ++(functionCount[SetGeometry]); + } + + void callUpdateGeometry() + { + // updateGeometry() is protected + QGraphicsWidget::updateGeometry(); + } + QMap functionCount; private: QMap m_eventCount; }; @@ -123,6 +150,8 @@ void tst_QGraphicsLayout::compressLayoutRequest() TestGraphicsWidget *tw = new TestGraphicsWidget(); scene.addItem(tw); view.show(); + + QTest::qWaitForWindowShown(&view); QGraphicsLinearLayout *lout = new QGraphicsLinearLayout(tw); for (int i = 0; i < 4; ++i) { QGraphicsWidget *gw = new QGraphicsWidget(tw); @@ -218,23 +247,27 @@ class TestLayout : public QGraphicsLinearLayout TestLayout(QGraphicsLayoutItem *parent = 0) : QGraphicsLinearLayout(parent) { - m_count = 0; - m_invalidateCount = 0; + setContentsMargins(0,0,0,0); + setSpacing(0); } - void setGeometry(const QRectF &rect) { - - ++m_count; + void setGeometry(const QRectF &rect) + { + ++(functionCount[SetGeometry]); QGraphicsLinearLayout::setGeometry(rect); } - void invalidate() { - ++m_invalidateCount; + void invalidate() + { + ++(functionCount[Invalidate]); QGraphicsLinearLayout::invalidate(); } - int m_invalidateCount; - int m_count; + void clearCounters() { + functionCount.clear(); + } + + QMap functionCount; }; void tst_QGraphicsLayout::verifyActivate() @@ -249,15 +282,47 @@ void tst_QGraphicsLayout::verifyActivate() lout->addItem(w); window->setLayout(lout); - QCOMPARE(lout->m_count, 0); + QCOMPARE(lout->functionCount[SetGeometry], 0); window->setVisible(false); - QCOMPARE(lout->m_count, 0); + QCOMPARE(lout->functionCount[SetGeometry], 0); window->setVisible(true); // on polish or the first time a widget is shown, the widget is resized. - QCOMPARE(lout->m_count, 1); + QCOMPARE(lout->functionCount[SetGeometry], 1); + +} + +static void clearAllCounters(TestGraphicsWidget *widget) +{ + if (!widget) + return; + widget->clearCounters(); + TestLayout *layout = static_cast(widget->layout()); + if (layout) { + layout->clearCounters(); + for (int i = layout->count() - 1; i >=0; --i) { + QGraphicsLayoutItem *item = layout->itemAt(i); + if (item->isLayout()) { + // ### Not used ATM + //TestLayout *lay = static_cast(static_cast(item)); + //clearAllCounters(lay); + } else { + TestGraphicsWidget *wid = static_cast(item); + clearAllCounters(wid); + } + } + } +} +static void activateAndReset(TestGraphicsWidget *widget) +{ + QApplication::sendPostedEvents(); + QApplication::processEvents(); + if (widget->layout()) + widget->layout()->activate(); + clearAllCounters(widget); } + void tst_QGraphicsLayout::invalidate() { QGraphicsLayout::setInstantInvalidatePropagation(true); @@ -265,76 +330,228 @@ void tst_QGraphicsLayout::invalidate() QGraphicsView view(&scene); TestGraphicsWidget *a = new TestGraphicsWidget; + a->setData(0, QString("a")); scene.addItem(a); TestLayout *alay = new TestLayout(a); TestGraphicsWidget *b = new TestGraphicsWidget; + b->setData(0, QString("b")); alay->addItem(b); TestLayout *blay = new TestLayout(b); TestGraphicsWidget *e = new TestGraphicsWidget; + e->setData(0, QString("e")); blay->addItem(e); TestGraphicsWidget *c = new TestGraphicsWidget; + c->setData(0, QString("c")); alay->addItem(c); TestLayout *clay = new TestLayout(c); TestGraphicsWidget *f = new TestGraphicsWidget; + f->setData(0, QString("f")); clay->addItem(f); TestGraphicsWidget *d = new TestGraphicsWidget; + d->setData(0, QString("d")); alay->addItem(d); TestLayout *dlay = new TestLayout(d); TestGraphicsWidget *g = new TestGraphicsWidget; + g->setData(0, QString("g")); dlay->addItem(g); view.show(); - alay->m_invalidateCount = 0; - blay->m_invalidateCount = 0; - clay->m_invalidateCount = 0; - dlay->m_invalidateCount = 0; - - QCoreApplication::sendPostedEvents(); - QCoreApplication::processEvents(); - - alay->activate(); - QCOMPARE(alay->isActivated(), true); - QCOMPARE(blay->isActivated(), true); - QCOMPARE(clay->isActivated(), true); - qDebug() << "alay->m_invalidateCount:" << alay->m_invalidateCount; - qDebug() << "blay->m_invalidateCount:" << blay->m_invalidateCount; - qDebug() << "clay->m_invalidateCount:" << clay->m_invalidateCount; - qDebug() << "dlay->m_invalidateCount:" << dlay->m_invalidateCount; - - a->clearEventCount(); - b->clearEventCount(); - c->clearEventCount(); - - blay->invalidate(); - QCOMPARE(alay->isActivated(), false); - QCOMPARE(blay->isActivated(), false); - QCOMPARE(clay->isActivated(), true); - QCOMPARE(a->eventCount(QEvent::LayoutRequest), 0); - QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); - QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); - - - alay->m_invalidateCount = 0; - blay->m_invalidateCount = 0; - clay->m_invalidateCount = 0; - dlay->m_invalidateCount = 0; - clay->invalidate(); - QCOMPARE(alay->isActivated(), false); - QCOMPARE(blay->isActivated(), false); - QCOMPARE(clay->isActivated(), false); - - QCoreApplication::sendPostedEvents(); - QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); - QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); - QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); - qDebug() << "alay->m_invalidateCount:" << alay->m_invalidateCount; - qDebug() << "blay->m_invalidateCount:" << blay->m_invalidateCount; - qDebug() << "clay->m_invalidateCount:" << clay->m_invalidateCount; - qDebug() << "dlay->m_invalidateCount:" << dlay->m_invalidateCount; + { + clearAllCounters(a); + + QCoreApplication::sendPostedEvents(); + QCoreApplication::processEvents(); + + alay->activate(); + QCOMPARE(alay->isActivated(), true); + QCOMPARE(blay->isActivated(), true); + QCOMPARE(clay->isActivated(), true); + QCOMPARE(dlay->isActivated(), true); + } + + { + clearAllCounters(a); + e->callUpdateGeometry(); + QCOMPARE(alay->isActivated(), false); + QCOMPARE(blay->isActivated(), false); + QCOMPARE(clay->isActivated(), true); + QCOMPARE(dlay->isActivated(), true); + QCOMPARE(a->eventCount(QEvent::LayoutRequest), 0); + QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); + QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); + QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0); + + // should only invalidate ascendants of e + QCOMPARE(blay->functionCount[Invalidate], 1); + QCOMPARE(alay->functionCount[Invalidate], 1); + // not siblings + QCOMPARE(clay->functionCount[Invalidate], 0); + QCOMPARE(dlay->functionCount[Invalidate], 0); + + QApplication::sendPostedEvents(); + QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(b->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); + QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0); + } + + + { + activateAndReset(a); + f->callUpdateGeometry(); + QCOMPARE(alay->isActivated(), false); + QCOMPARE(blay->isActivated(), true); + QCOMPARE(clay->isActivated(), false); + QCOMPARE(dlay->isActivated(), true); + + QCoreApplication::sendPostedEvents(); + QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); + QCOMPARE(c->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0); + + QCOMPARE(a->functionCount[SetGeometry], 1); + QCOMPARE(alay->functionCount[SetGeometry], 1); + + QCOMPARE(b->functionCount[SetGeometry], 1); + QCOMPARE(c->functionCount[SetGeometry], 1); + QCOMPARE(d->functionCount[SetGeometry], 1); + // Since nothing really changed, blay and dlay don't need + // to be resized. + QCOMPARE(blay->functionCount[SetGeometry], 0); + QCOMPARE(clay->functionCount[SetGeometry], 1); + QCOMPARE(dlay->functionCount[SetGeometry], 0); + + QCOMPARE(f->functionCount[SetGeometry], 1); + + QCOMPARE(a->size(), QSizeF(150, 50)); + } + + { + activateAndReset(a); + f->setPreferredSize(QSizeF(60,50)); + QCOMPARE(alay->isActivated(), false); + QCOMPARE(blay->isActivated(), true); + QCOMPARE(clay->isActivated(), false); + QCOMPARE(dlay->isActivated(), true); + + QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); + QCoreApplication::sendPostedEvents(); + QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); + QCOMPARE(c->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0); + + QCOMPARE(a->functionCount[SetGeometry], 1); + QCOMPARE(alay->functionCount[SetGeometry], 1); + + QCOMPARE(b->functionCount[SetGeometry], 1); + QCOMPARE(c->functionCount[SetGeometry], 1); + QCOMPARE(d->functionCount[SetGeometry], 1); + // f actually got wider, need to rearrange its siblings + QCOMPARE(blay->functionCount[SetGeometry], 1); + QCOMPARE(clay->functionCount[SetGeometry], 1); + QCOMPARE(dlay->functionCount[SetGeometry], 1); + + QCOMPARE(e->functionCount[SetGeometry], 1); + QCOMPARE(f->functionCount[SetGeometry], 1); + QCOMPARE(g->functionCount[SetGeometry], 1); + + QVERIFY(e->size().width() < f->size().width()); + QVERIFY(g->size().width() < f->size().width()); + } + + { + // resize f so much that it'll force a resize of the top widget + // this will currently generate two setGeometry() calls on the child layout + // of the top widget. + activateAndReset(a); + f->setPreferredSize(QSizeF()); + f->setMinimumSize(QSizeF(200,50)); + QCOMPARE(alay->isActivated(), false); + QCOMPARE(blay->isActivated(), true); + QCOMPARE(clay->isActivated(), false); + QCOMPARE(dlay->isActivated(), true); + + QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); + QCoreApplication::sendPostedEvents(); + QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(b->eventCount(QEvent::LayoutRequest), 0); + QCOMPARE(c->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(d->eventCount(QEvent::LayoutRequest), 0); + + QCOMPARE(a->functionCount[SetGeometry], 1); + + /* well, ideally one call to setGeometry(), but it will currently + * get two calls to setGeometry(): + * 1. The first LayoutRequest will call activate() - that will call + * setGeometry() on the layout. This geometry will be based on + * the widget geometry which is not correct at this moment. + * (it is still 150 wide) + * 2. Next, we check if the widget is top level, and then we call + * parentWidget->resize(parentWidget->size()); + * This will be adjusted to be minimum 200 pixels wide. + * The new size will then be propagated down to the layout + * + */ + QCOMPARE(alay->functionCount[SetGeometry], 2); + + QCOMPARE(b->functionCount[SetGeometry], 2); + QCOMPARE(c->functionCount[SetGeometry], 2); + QCOMPARE(d->functionCount[SetGeometry], 2); + // f actually got wider, need to rearrange its siblings + QCOMPARE(blay->functionCount[SetGeometry], 1); + QCOMPARE(clay->functionCount[SetGeometry], 1); + QCOMPARE(dlay->functionCount[SetGeometry], 1); + + QCOMPARE(e->functionCount[SetGeometry], 1); + QCOMPARE(f->functionCount[SetGeometry], 1); + QCOMPARE(g->functionCount[SetGeometry], 1); + + QVERIFY(e->size().width() < f->size().width()); + QVERIFY(g->size().width() < f->size().width()); + } + + { + f->setPreferredSize(QSizeF()); + f->setMinimumSize(QSizeF()); + a->adjustSize(); + activateAndReset(a); + // update two different leaf widgets, + // eventCount and functionCount should never be >= 2 + e->callUpdateGeometry(); + g->callUpdateGeometry(); + QCOMPARE(alay->isActivated(), false); + QCOMPARE(blay->isActivated(), false); + QCOMPARE(clay->isActivated(), true); + QCOMPARE(dlay->isActivated(), false); + + QCoreApplication::sendPostedEvents(); + QCOMPARE(a->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(b->eventCount(QEvent::LayoutRequest), 1); + QCOMPARE(c->eventCount(QEvent::LayoutRequest), 0); + QCOMPARE(d->eventCount(QEvent::LayoutRequest), 1); + + QCOMPARE(a->functionCount[SetGeometry], 1); + QCOMPARE(alay->functionCount[SetGeometry], 1); + + QCOMPARE(b->functionCount[SetGeometry], 1); + QCOMPARE(c->functionCount[SetGeometry], 1); + QCOMPARE(d->functionCount[SetGeometry], 1); + // f actually got wider, need to rearrange its siblings + QCOMPARE(blay->functionCount[SetGeometry], 1); + QCOMPARE(clay->functionCount[SetGeometry], 0); + QCOMPARE(dlay->functionCount[SetGeometry], 1); + + QCOMPARE(e->functionCount[SetGeometry], 1); + QCOMPARE(f->functionCount[SetGeometry], 0); + QCOMPARE(g->functionCount[SetGeometry], 1); + + } QGraphicsLayout::setInstantInvalidatePropagation(false); } -- cgit v0.12 From fae8bb9f583b416bf47208561c38e0b102f8578c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Fri, 18 Mar 2011 16:33:31 +0100 Subject: Manual test for layout flickering --- tests/manual/qgraphicslayout/flicker/flicker.pro | 8 + tests/manual/qgraphicslayout/flicker/main.cpp | 15 ++ tests/manual/qgraphicslayout/flicker/window.cpp | 32 +++ tests/manual/qgraphicslayout/flicker/window.h | 243 +++++++++++++++++++++++ 4 files changed, 298 insertions(+) create mode 100644 tests/manual/qgraphicslayout/flicker/flicker.pro create mode 100644 tests/manual/qgraphicslayout/flicker/main.cpp create mode 100644 tests/manual/qgraphicslayout/flicker/window.cpp create mode 100644 tests/manual/qgraphicslayout/flicker/window.h diff --git a/tests/manual/qgraphicslayout/flicker/flicker.pro b/tests/manual/qgraphicslayout/flicker/flicker.pro new file mode 100644 index 0000000..323a30f --- /dev/null +++ b/tests/manual/qgraphicslayout/flicker/flicker.pro @@ -0,0 +1,8 @@ +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +# Input +HEADERS += window.h +SOURCES += main.cpp window.cpp diff --git a/tests/manual/qgraphicslayout/flicker/main.cpp b/tests/manual/qgraphicslayout/flicker/main.cpp new file mode 100644 index 0000000..838d45f --- /dev/null +++ b/tests/manual/qgraphicslayout/flicker/main.cpp @@ -0,0 +1,15 @@ +#include +#include +#include "window.h" + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + Window *window = new Window(); + window->resize(800, 600); + + window->show(); + + return app.exec(); + +} diff --git a/tests/manual/qgraphicslayout/flicker/window.cpp b/tests/manual/qgraphicslayout/flicker/window.cpp new file mode 100644 index 0000000..d193ad1 --- /dev/null +++ b/tests/manual/qgraphicslayout/flicker/window.cpp @@ -0,0 +1,32 @@ +#include "window.h" + +void SlowWidget::setGeometry(const QRectF &rect) +{ + bool reiterate = false; + Statistics &stats = *m_stats; + if (stats.relayoutClicked) { + ++(stats.setGeometryTracker[this]); + ++stats.setGeometryCount; + qDebug() << "setGeometryCount:" << stats.setGeometryCount; + if (stats.setGeometryTracker.count() == m_window->m_depthSpinBox->value()) { + ++stats.currentBenchmarkIteration; + qDebug() << "currentBenchmarkIteration:" << stats.currentBenchmarkIteration; + if (stats.currentBenchmarkIteration == m_window->m_benchmarkIterationsSpinBox->value()) { + if (stats.output) + stats.output->setText(tr("DONE. Elapsed: %1, setGeometryCount: %2").arg(stats.time.elapsed()).arg(stats.setGeometryCount)); + } else { + reiterate = true; + } + stats.setGeometryTracker.clear(); + + } + } + + QGraphicsWidget::setGeometry(rect); + + if (reiterate) { + m_window->doAgain(); + //QTimer::singleShot(0, m_window, SLOT(doAgain())); + } +} + diff --git a/tests/manual/qgraphicslayout/flicker/window.h b/tests/manual/qgraphicslayout/flicker/window.h new file mode 100644 index 0000000..df1fc82 --- /dev/null +++ b/tests/manual/qgraphicslayout/flicker/window.h @@ -0,0 +1,243 @@ +#ifndef WINDOW_H +#define WINDOW_H + + +#include + +static void qSleep(int msec) +{ + + struct Thread : public QThread + { + static void wait(int msec) + { + QThread::msleep(msec); + } + }; + Thread::wait(msec); +} + +struct Statistics { + Statistics() : output(0), + setGeometryCount(0), currentBenchmarkIteration(0), relayoutClicked(false), sleepMsecs(0) + { + } + QMap setGeometryTracker; + QTime time; + int setGeometryCount; + int sleepMsecs; + QLabel *output; + void sleep() + { + qSleep(sleepMsecs); + } + int currentBenchmarkIteration; + bool relayoutClicked; + +}; + + +class Window; + +class SlowWidget : public QGraphicsWidget { +public: + SlowWidget(QGraphicsWidget *w = 0, Qt::WindowFlags wFlags = 0) : QGraphicsWidget(w, wFlags) + { + m_window = 0; + } + + void setStats(Statistics *stats) + { + m_stats = stats; + } + + void setWindow(Window *window) + { + m_window = window; + } + + void setGeometry(const QRectF &rect); + + bool event(QEvent *e) + { + if (e->type() == QEvent::LayoutRequest) { + if (m_stats->sleepMsecs > 0) { + m_stats->sleep(); + qDebug("sleep %d ms\n", m_stats->sleepMsecs); + } + } + return QGraphicsWidget::event(e); + } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) + { + Q_UNUSED(option); + Q_UNUSED(widget); + painter->setBrush(m_brush); + painter->drawRoundRect(rect()); + painter->drawLine(rect().topLeft(), rect().bottomRight()); + painter->drawLine(rect().bottomLeft(), rect().topRight()); + } + + void setBrush(const QBrush &brush) + { + m_brush = brush; + } +private: + QBrush m_brush; + Statistics *m_stats; + Window *m_window; +}; + +class Window : public QWidget { + Q_OBJECT +public: + Window() : QWidget() + { + QGraphicsView *m_view = new QGraphicsView(&scene); + + m_window = 0; + m_leaf = 0; + + m_button = new QPushButton(tr("Relayout")); + m_button->setObjectName("button"); + + m_sleepLabel = new QLabel(tr("Sleep:")); + m_sleepSpinBox = new QSpinBox; + m_sleepSpinBox->setRange(0, 1000); + m_sleepSpinBox->setSingleStep(10); + + m_depthLabel = new QLabel(tr("Depth:")); + m_depthSpinBox = new QSpinBox; + m_depthSpinBox->setObjectName("depthSpinBox"); + m_depthSpinBox->setRange(1, 200); + m_depthSpinBox->setSingleStep(5); + + m_benchmarkIterationsLabel = new QLabel(tr("Benchmark iterations")); + m_benchmarkIterationsSpinBox = new QSpinBox; + m_benchmarkIterationsSpinBox->setObjectName("benchmarkIterationsSpinBox"); + m_benchmarkIterationsSpinBox->setRange(1, 1000); + m_benchmarkIterationsSpinBox->setValue(41); + m_benchmarkIterationsSpinBox->setSingleStep(10); + + m_instantCheckBox = new QCheckBox(tr("Instant propagation")); + m_instantCheckBox->setObjectName("instantPropagationCheckbox"); + QGraphicsLayout::setInstantInvalidatePropagation(true); + m_instantCheckBox->setChecked(QGraphicsLayout::instantInvalidatePropagation()); + + m_resultLabel = new QLabel(tr("Press relayout to start test")); + + QHBoxLayout *hbox = new QHBoxLayout; + hbox->addWidget(m_sleepLabel); + hbox->addWidget(m_sleepSpinBox); + hbox->addWidget(m_depthLabel); + hbox->addWidget(m_depthSpinBox); + hbox->addWidget(m_benchmarkIterationsLabel); + hbox->addWidget(m_benchmarkIterationsSpinBox); + hbox->addWidget(m_instantCheckBox); + hbox->addWidget(m_resultLabel); + hbox->addStretch(); + hbox->addWidget(m_button); + + QVBoxLayout *vbox = new QVBoxLayout; + vbox->addWidget(m_view); + vbox->addLayout(hbox); + setLayout(vbox); + + metaObject()->connectSlotsByName(this); + + m_depthSpinBox->setValue(20); // triggers purposedly on_depthSpinBox_valueChanged + } + +private slots: + void on_depthSpinBox_valueChanged(int value) + { + m_stats.relayoutClicked = false; + if (m_window) { + QApplication::processEvents(); + delete m_window; + } + m_window = new SlowWidget(0, Qt::Window); + m_window->setStats(&m_stats); + m_window->setWindow(this); + QColor col(Qt::black); + m_window->setBrush(col); + scene.addItem(m_window); + m_leaf = 0; + const int depth = value; + SlowWidget *parent = m_window; + for (int i = 1; i < depth; ++i) { + QGraphicsLinearLayout *l = new QGraphicsLinearLayout(parent); + l->setContentsMargins(2,2,2,2); + SlowWidget *child = new SlowWidget; + QColor col; + col.setHsl(0, 0, 255*i/(depth - 1)); + child->setBrush(col); + child->setStats(&m_stats); + child->setWindow(this); + l->addItem(child); + parent = child; + } + m_leaf = parent; + } + + void on_button_clicked(bool /*check = false*/) + { + m_stats.relayoutClicked = true; + if (m_leaf) { + QSizeF sz = m_leaf->size(); + int w = int(sz.width()); + w^=16; + sz = QSizeF(w,w); + m_stats.output = m_resultLabel; + m_stats.output->setText(QString("wait...")); + m_stats.setGeometryCount = 0; + m_stats.setGeometryTracker.clear(); + m_stats.sleepMsecs = m_sleepSpinBox->value(); + m_stats.time.start(); + m_stats.currentBenchmarkIteration = 0; + m_leaf->setMinimumSize(sz); + m_leaf->setMaximumSize(sz); + } + } + + void on_instantPropagationCheckbox_toggled(bool checked) + { + QGraphicsLayout::setInstantInvalidatePropagation(checked); + } + +public slots: + void doAgain() + { + if (m_leaf) { + QSizeF sz = m_leaf->size(); + int w = int(sz.width()); + w^=16; + sz = QSizeF(w,w); + m_leaf->setMinimumSize(sz); + m_leaf->setMaximumSize(sz); + } + } + +private: +public: + QGraphicsScene scene; + QGraphicsView *m_view; + QPushButton *m_button; + QLabel *m_sleepLabel; + QSpinBox *m_sleepSpinBox; + QLabel *m_depthLabel; + QSpinBox *m_depthSpinBox; + QLabel *m_benchmarkIterationsLabel; + QSpinBox *m_benchmarkIterationsSpinBox; + QCheckBox *m_instantCheckBox; + QLabel *m_resultLabel; + QGraphicsWidget *m_leaf; + SlowWidget *m_window; + Statistics m_stats; + + +}; + + +#endif //WINDOW_H -- cgit v0.12 From cb503a3f4901c0b017374f099b0de8c0c4c50648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Arve=20S=C3=A6ther?= Date: Fri, 1 Apr 2011 14:50:18 +0200 Subject: Benchmark for layout hierarchies --- tests/benchmarks/gui/graphicsview/graphicsview.pro | 1 + .../qgraphicslayout/qgraphicslayout.pro | 6 + .../qgraphicslayout/tst_qgraphicslayout.cpp | 153 +++++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 tests/benchmarks/gui/graphicsview/qgraphicslayout/qgraphicslayout.pro create mode 100644 tests/benchmarks/gui/graphicsview/qgraphicslayout/tst_qgraphicslayout.cpp diff --git a/tests/benchmarks/gui/graphicsview/graphicsview.pro b/tests/benchmarks/gui/graphicsview/graphicsview.pro index e4fed19..1509466 100644 --- a/tests/benchmarks/gui/graphicsview/graphicsview.pro +++ b/tests/benchmarks/gui/graphicsview/graphicsview.pro @@ -3,6 +3,7 @@ SUBDIRS = \ functional \ qgraphicsanchorlayout \ qgraphicsitem \ + qgraphicslayout \ qgraphicsscene \ qgraphicsview \ qgraphicswidget diff --git a/tests/benchmarks/gui/graphicsview/qgraphicslayout/qgraphicslayout.pro b/tests/benchmarks/gui/graphicsview/qgraphicslayout/qgraphicslayout.pro new file mode 100644 index 0000000..19e2979 --- /dev/null +++ b/tests/benchmarks/gui/graphicsview/qgraphicslayout/qgraphicslayout.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_bench_qgraphicslayout + +SOURCES += tst_qgraphicslayout.cpp + diff --git a/tests/benchmarks/gui/graphicsview/qgraphicslayout/tst_qgraphicslayout.cpp b/tests/benchmarks/gui/graphicsview/qgraphicslayout/tst_qgraphicslayout.cpp new file mode 100644 index 0000000..4bdcfb3 --- /dev/null +++ b/tests/benchmarks/gui/graphicsview/qgraphicslayout/tst_qgraphicslayout.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +class tst_QGraphicsLayout : public QObject +{ + Q_OBJECT +public: + tst_QGraphicsLayout() {} + ~tst_QGraphicsLayout() {} + +private slots: + void invalidate(); +}; + + +class RectWidget : public QGraphicsWidget +{ +public: + RectWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0) : QGraphicsWidget(parent, wFlags), setGeometryCalls(0) {} + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) + { + Q_UNUSED(option); + Q_UNUSED(widget); + painter->drawRoundRect(rect()); + painter->drawLine(rect().topLeft(), rect().bottomRight()); + painter->drawLine(rect().bottomLeft(), rect().topRight()); + } + + void setGeometry(const QRectF &rect) + { + //qDebug() << "setGeometry():" << this->data(0).toString(); + setGeometryCalls->insert(this, rect); + QGraphicsWidget::setGeometry(rect); + } + + void callUpdateGeometry() { + QGraphicsWidget::updateGeometry(); + } + + QMap *setGeometryCalls; +}; + +/** + * Test to see how much time is needed to resize all widgets in a + * layout-widget-layout-widget-.... hierarchy from the point where a + * leaf widget changes its size hint. (updateGeometry() is called). + * + * If you run the test for 4.7 you'll get some really high numbers, but + * that's because they also include painting (and possible processing of + * some other events). + */ +void tst_QGraphicsLayout::invalidate() +{ + QGraphicsLayout::setInstantInvalidatePropagation(true); + QGraphicsScene scene; + QGraphicsView *view = new QGraphicsView(&scene); + QMap setGeometryCalls; + + RectWidget *window = new RectWidget(0, Qt::Window); + window->setGeometryCalls = &setGeometryCalls; + window->setData(0, QString(QChar('a'))); + + scene.addItem(window); + RectWidget *leaf = 0; + const int depth = 100; + RectWidget *parent = window; + for (int i = 1; i < depth; ++i) { + QGraphicsLinearLayout *l = new QGraphicsLinearLayout(parent); + l->setContentsMargins(0,0,0,0); + RectWidget *child = new RectWidget; + child->setData(0, QString(QChar('a' + i))); + child->setGeometryCalls = &setGeometryCalls; + l->addItem(child); + parent = child; + } + leaf = parent; + leaf->setMinimumSize(QSizeF(1,1)); + + view->show(); + + QTest::qWaitForWindowShown(view); + + // ...then measure... + + int pass = 1; + + // should be as small as possible, to reduce overhead of painting + QSizeF size(1, 1); + setGeometryCalls.clear(); + QBENCHMARK { + leaf->setMinimumSize(size); + leaf->setMaximumSize(size); + while (setGeometryCalls.count() < depth) { + QApplication::sendPostedEvents(); + } + // force a resize on each widget, this will ensure + // that each iteration will resize all 50 widgets + int w = int(size.width()); + w^=2; + size.setWidth(w); + } + delete view; + QGraphicsLayout::setInstantInvalidatePropagation(false); +} + +QTEST_MAIN(tst_QGraphicsLayout) + +#include "tst_qgraphicslayout.moc" -- cgit v0.12 From 6414bda3218790fb8a20a8ff5b3acf6fc6e206da Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Thu, 14 Apr 2011 13:40:36 +0200 Subject: qdoc: Completed task QTBUG-18733 --- tools/qdoc3/codemarker.h | 3 +- tools/qdoc3/ditaxmlgenerator.cpp | 76 +++++++++++++++++++++++------ tools/qdoc3/ditaxmlgenerator.h | 13 +++-- tools/qdoc3/htmlgenerator.cpp | 101 +-------------------------------------- tools/qdoc3/pagegenerator.cpp | 6 --- 5 files changed, 74 insertions(+), 125 deletions(-) diff --git a/tools/qdoc3/codemarker.h b/tools/qdoc3/codemarker.h index 21bc31f..00660e7 100644 --- a/tools/qdoc3/codemarker.h +++ b/tools/qdoc3/codemarker.h @@ -165,10 +165,11 @@ class CodeMarker static const Node *nodeForString(const QString& string); static QString stringForNode(const Node *node); + QString typified(const QString &string); + protected: virtual QString sortName(const Node *node); QString protect(const QString &string); - QString typified(const QString &string); QString taggedNode(const Node* node); #ifdef QDOC_QML QString taggedQmlNode(const Node* node); diff --git a/tools/qdoc3/ditaxmlgenerator.cpp b/tools/qdoc3/ditaxmlgenerator.cpp index 69afde9..e394249 100644 --- a/tools/qdoc3/ditaxmlgenerator.cpp +++ b/tools/qdoc3/ditaxmlgenerator.cpp @@ -92,6 +92,7 @@ QString DitaXmlGenerator::ditaTags[] = "apiDesc", "APIMap", "apiName", + "apiRelation", "audience", "author", "b", @@ -284,14 +285,15 @@ void DitaXmlGenerator::writeCharacters(const QString& text) with the \a href attribute and the \a text. */ void DitaXmlGenerator::addLink(const QString& href, - const QStringRef& text) + const QStringRef& text, + DitaTag t) { if (!href.isEmpty()) { - writeStartTag(DT_xref); + writeStartTag(t); // formathtml xmlWriter().writeAttribute("href", href); writeCharacters(text.toString()); - writeEndTag(); // + writeEndTag(); // } else { writeCharacters(text.toString()); @@ -1718,7 +1720,7 @@ DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* mark */ generateHeader(inner, fullTitle); generateBrief(inner, marker); // - writeProlog(inner,marker); + writeProlog(inner); writeStartTag(DT_cxxClassDetail); writeStartTag(DT_cxxClassDefinition); @@ -1838,7 +1840,7 @@ DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* mark generateHeader(inner, fullTitle); generateBrief(inner, marker); // - writeProlog(inner,marker); + writeProlog(inner); writeStartTag(DT_cxxClassDetail); writeStartTag(DT_cxxClassDefinition); @@ -1974,7 +1976,7 @@ DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* mark */ generateHeader(inner, fullTitle); generateBrief(inner, marker); // - writeProlog(inner,marker); + writeProlog(inner); writeStartTag(DT_cxxClassDetail); enterApiDesc(QString(),title); @@ -2093,7 +2095,7 @@ DitaXmlGenerator::generateClassLikeNode(const InnerNode* inner, CodeMarker* mark generateHeader(inner, fullTitle); generateBrief(inner, marker); // - writeProlog(inner,marker); + writeProlog(inner); writeStartTag(DT_cxxClassDetail); enterApiDesc(QString(),title); @@ -2195,7 +2197,7 @@ void DitaXmlGenerator::generateFakeNode(const FakeNode* fake, CodeMarker* marker generateHeader(fake, fullTitle); generateBrief(fake, marker); // - writeProlog(fake, marker); + writeProlog(fake); writeStartTag(DT_body); enterSection(QString(),QString()); @@ -4712,7 +4714,7 @@ void DitaXmlGenerator::writeLocation(const Node* n) Write the elements. */ void DitaXmlGenerator::writeFunctions(const Section& s, - const Node* n, + const InnerNode* parent, CodeMarker* marker, const QString& attribute) { @@ -4775,7 +4777,7 @@ void DitaXmlGenerator::writeFunctions(const Section& s, } } - if (fn->name() == n->name()) { + if (fn->name() == parent->name()) { writeStartTag(DT_cxxFunctionConstructor); xmlWriter().writeAttribute("name","constructor"); xmlWriter().writeAttribute("value","constructor"); @@ -4789,7 +4791,8 @@ void DitaXmlGenerator::writeFunctions(const Section& s, } else { writeStartTag(DT_cxxFunctionDeclaredType); - writeCharacters(fn->returnType()); + QString src = marker->typified(fn->returnType()); + replaceTypesWithLinks(fn,parent,marker,src); writeEndTag(); // } @@ -4825,7 +4828,7 @@ void DitaXmlGenerator::writeFunctions(const Section& s, writeEndTag(); // } } - writeParameters(fn); + writeParameters(fn,parent,marker); writeLocation(fn); writeEndTag(); // @@ -4846,10 +4849,51 @@ void DitaXmlGenerator::writeFunctions(const Section& s, } } +static const QString typeTag("type"); +static const QChar charLangle = '<'; +static const QChar charAt = '@'; + +/*! + This function replaces class and enum names with + elements, i.e. links. + */ +void DitaXmlGenerator::replaceTypesWithLinks(const Node* n, + const InnerNode* parent, + CodeMarker* marker, + QString& src) +{ + QStringRef arg; + QStringRef par1; + int srcSize = src.size(); + QString text; + for (int i=0; iresolveTarget(arg.toString(), myTree, parent, n); + addLink(linkForNode(tn,parent),arg,DT_apiRelation); + } + } + else { + text += src.at(i++); + } + } + if (!text.isEmpty()) { + writeCharacters(text); + text.clear(); + } +} + /*! This function writes the element. */ -void DitaXmlGenerator::writeParameters(const FunctionNode* fn) +void DitaXmlGenerator::writeParameters(const FunctionNode* fn, + const InnerNode* parent, + CodeMarker* marker) { const QList& parameters = fn->parameters(); if (!parameters.isEmpty()) { @@ -4858,7 +4902,9 @@ void DitaXmlGenerator::writeParameters(const FunctionNode* fn) while (p != parameters.end()) { writeStartTag(DT_cxxFunctionParameter); writeStartTag(DT_cxxFunctionParameterDeclaredType); - writeCharacters((*p).leftType()); + QString src = marker->typified((*p).leftType()); + replaceTypesWithLinks(fn,parent,marker,src); + //writeCharacters((*p).leftType()); if (!(*p).rightType().isEmpty()) writeCharacters((*p).rightType()); writeEndTag(); // @@ -5695,7 +5741,7 @@ QString DitaXmlGenerator::metadataDefault(DitaTag t) const */ void -DitaXmlGenerator::writeProlog(const InnerNode* inner, CodeMarker* marker) +DitaXmlGenerator::writeProlog(const InnerNode* inner) { if (!inner) return; diff --git a/tools/qdoc3/ditaxmlgenerator.h b/tools/qdoc3/ditaxmlgenerator.h index ffca234..0044eff 100644 --- a/tools/qdoc3/ditaxmlgenerator.h +++ b/tools/qdoc3/ditaxmlgenerator.h @@ -87,6 +87,7 @@ class DitaXmlGenerator : public PageGenerator DT_apiDesc, DT_APIMap, DT_apiName, + DT_apiRelation, DT_audience, DT_author, DT_b, @@ -292,11 +293,15 @@ class DitaXmlGenerator : public PageGenerator void writeDerivations(const ClassNode* cn, CodeMarker* marker); void writeLocation(const Node* n); void writeFunctions(const Section& s, - const Node* n, + const InnerNode* parent, CodeMarker* marker, const QString& attribute = QString()); void writeNestedClasses(const Section& s, const Node* n); - void writeParameters(const FunctionNode* fn); + void replaceTypesWithLinks(const Node* n, + const InnerNode* parent, + CodeMarker* marker, + QString& src); + void writeParameters(const FunctionNode* fn, const InnerNode* parent, CodeMarker* marker); void writeEnumerations(const Section& s, CodeMarker* marker, const QString& attribute = QString()); @@ -315,7 +320,7 @@ class DitaXmlGenerator : public PageGenerator void writePropertyParameter(const QString& tag, const NodeList& nlist); void writeRelatedLinks(const FakeNode* fake, CodeMarker* marker); void writeLink(const Node* node, const QString& tex, const QString& role); - void writeProlog(const InnerNode* inner, CodeMarker* marker); + void writeProlog(const InnerNode* inner); bool writeMetadataElement(const InnerNode* inner, DitaXmlGenerator::DitaTag t, bool force=true); @@ -438,7 +443,7 @@ class DitaXmlGenerator : public PageGenerator virtual void generateInnerNode(const InnerNode* node); QXmlStreamWriter& xmlWriter(); void writeApiDesc(const Node* node, CodeMarker* marker, const QString& title); - void addLink(const QString& href, const QStringRef& text); + void addLink(const QString& href, const QStringRef& text, DitaTag t = DT_xref); void writeDitaMap(); void writeStartTag(DitaTag t); void writeEndTag(DitaTag t=DT_NONE); diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 88bc3e2..a6cf646 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -93,104 +93,6 @@ static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)()"); static QRegExp spanTag(""); static QRegExp unknownTag("]*>"); -bool parseArg(const QString &src, - const QString &tag, - int *pos, - int n, - QStringRef *contents, - QStringRef *par1 = 0, - bool debug = false) -{ -#define SKIP_CHAR(c) \ - if (debug) \ - qDebug() << "looking for " << c << " at " << QString(src.data() + i, n - i); \ - if (i >= n || src[i] != c) { \ - if (debug) \ - qDebug() << " char '" << c << "' not found"; \ - return false; \ - } \ - ++i; - - -#define SKIP_SPACE \ - while (i < n && src[i] == ' ') \ - ++i; - - int i = *pos; - int j = i; - - // assume "<@" has been parsed outside - //SKIP_CHAR('<'); - //SKIP_CHAR('@'); - - if (tag != QStringRef(&src, i, tag.length())) { - if (0 && debug) - qDebug() << "tag " << tag << " not found at " << i; - return false; - } - - if (debug) - qDebug() << "haystack:" << src << "needle:" << tag << "i:" <).*()"); - if (par1) { - SKIP_SPACE; - // read parameter name - j = i; - while (i < n && src[i].isLetter()) - ++i; - if (src[i] == '=') { - if (debug) - qDebug() << "read parameter" << QString(src.data() + j, i - j); - SKIP_CHAR('='); - SKIP_CHAR('"'); - // skip parameter name - j = i; - while (i < n && src[i] != '"') - ++i; - *par1 = QStringRef(&src, j, i - j); - SKIP_CHAR('"'); - SKIP_SPACE; - } else { - if (debug) - qDebug() << "no optional parameter found"; - } - } - SKIP_SPACE; - SKIP_CHAR('>'); - - // find contents up to closing " - j = i; - for (; true; ++i) { - if (i + 4 + tag.length() > n) - return false; - if (src[i] != '<') - continue; - if (src[i + 1] != '/') - continue; - if (src[i + 2] != '@') - continue; - if (tag != QStringRef(&src, i + 3, tag.length())) - continue; - if (src[i + 3 + tag.length()] != '>') - continue; - break; - } - - *contents = QStringRef(&src, j, i - j); - - i += tag.length() + 4; - - *pos = i; - if (debug) - qDebug() << " tag " << tag << " found: pos now: " << i; - return true; -#undef SKIP_CHAR -} - static void addLink(const QString &linkTarget, const QStringRef &nestedStuff, QString *res) @@ -2849,7 +2751,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, static const QString headerTag("headerfile"); static const QString funcTag("func"); static const QString linkTag("link"); - + // replace all <@link> tags: "(<@link node=\"([^\"]+)\">).*()" bool done = false; for (int i = 0, srcSize = src.size(); i < srcSize;) { @@ -2884,6 +2786,7 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, if (src.at(i) == charLangle && src.at(i + 1) == charAt) { i += 2; if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) { + const Node* n = marker->resolveTarget(par1.toString(), myTree, relative); diff --git a/tools/qdoc3/pagegenerator.cpp b/tools/qdoc3/pagegenerator.cpp index d5564f7..d331d41 100644 --- a/tools/qdoc3/pagegenerator.cpp +++ b/tools/qdoc3/pagegenerator.cpp @@ -70,12 +70,6 @@ PageGenerator::~PageGenerator() endSubPage(); } -static QRegExp linkTag("(<@link node=\"([^\"]+)\">).*()"); -static QRegExp funcTag("(<@func target=\"([^\"]*)\">)(.*)()"); -static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)()"); -static QRegExp spanTag(""); -static QRegExp unknownTag("]*>"); - bool PageGenerator::parseArg(const QString& src, const QString& tag, int* pos, -- cgit v0.12 From 7b6a7f475119878681c9d0c06b29896ec3fe72c3 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Thu, 14 Apr 2011 13:58:25 +0200 Subject: Fix licence headers again for MR 900 See commit b00089261eafbdf5f92ed94d7fb20b402bfcaeb2 Reviewed-by: Trust me --- src/gui/itemviews/qidentityproxymodel.cpp | 21 +++++++------- src/gui/itemviews/qidentityproxymodel.h | 20 ++++++------- .../tst_qidentityproxymodel.cpp | 33 +++++++++++++--------- 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/gui/itemviews/qidentityproxymodel.cpp b/src/gui/itemviews/qidentityproxymodel.cpp index 9396e61..fcc0504 100644 --- a/src/gui/itemviews/qidentityproxymodel.cpp +++ b/src/gui/itemviews/qidentityproxymodel.cpp @@ -20,20 +20,21 @@ ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. ** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** +** $QT_END_LICENSE$ ** ****************************************************************************/ + #include "qidentityproxymodel.h" #ifndef QT_NO_IDENTITYPROXYMODEL diff --git a/src/gui/itemviews/qidentityproxymodel.h b/src/gui/itemviews/qidentityproxymodel.h index b60aa0b..9845533 100644 --- a/src/gui/itemviews/qidentityproxymodel.h +++ b/src/gui/itemviews/qidentityproxymodel.h @@ -20,17 +20,17 @@ ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. ** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** +** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp b/tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp index bbcdb4c..cfc3f1a 100644 --- a/tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp +++ b/tests/auto/qidentityproxymodel/tst_qidentityproxymodel.cpp @@ -1,13 +1,18 @@ /**************************************************************************** ** -** Copyright (C) 2011 Klarälvdalens Datakonsult AB, -** a KDAB Group company, info@kdab.com, -** author Stephen Kelly +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly ** All rights reserved. -** Contact: Nokia Corporation (info@qt.nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software @@ -20,17 +25,17 @@ ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** ** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. +** $QT_END_LICENSE$ ** ****************************************************************************/ -- cgit v0.12 From ea585d567bf0970c57e31846da044295d80774ba Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Thu, 14 Apr 2011 14:12:56 +0200 Subject: Build fix on QMenuBar Reviewed-By: gabi Merge-Request: 916 --- src/gui/widgets/qmenubar.cpp | 2 +- src/gui/widgets/qmenubarimpl.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index 357c0fa..a968404 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -441,7 +441,7 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const QSize sz; //calc what I think the size is.. - i f(action->isSeparator()) { + if (action->isSeparator()) { if (style->styleHint(QStyle::SH_DrawMenuBarSeparator, 0, q)) separator = i; continue; //we don't really position these! diff --git a/src/gui/widgets/qmenubarimpl.cpp b/src/gui/widgets/qmenubarimpl.cpp index d402507..db10c72 100644 --- a/src/gui/widgets/qmenubarimpl.cpp +++ b/src/gui/widgets/qmenubarimpl.cpp @@ -120,12 +120,10 @@ void QMenuBarImpl::actionEvent(QActionEvent *e) void QMenuBarImpl::handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow) { -#ifdef Q_WS_X11 Q_UNUSED(oldParent) Q_UNUSED(newParent) Q_UNUSED(oldWindow) Q_UNUSED(newWindow) -#endif #ifdef Q_WS_MAC if (isNativeMenuBar() && !macWidgetHasNativeMenubar(newParent)) { -- cgit v0.12 From 7cc4ffce36c24596630ca83cd6418869d6383670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Thu, 14 Apr 2011 14:33:02 +0200 Subject: Compile fix in qdrawhelper_sse2.cpp. --- src/gui/painting/qdrawhelper_sse2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index fdab95f..c6bd339 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -523,7 +523,7 @@ public: static inline Int32x4 v_toInt(Float32x4 x) { return _mm_cvttps_epi32(x); } - static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return (__m128i)_mm_cmpgt_ps(a, b); } + static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return _mm_castps_si128(_mm_cmpgt_ps(a, b)); } }; const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, -- cgit v0.12 From 68542b72f53f52df43063677e24994463872e81b Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Thu, 14 Apr 2011 14:50:33 +0200 Subject: Reverting merge request 916 Revert "Build fix on QMenuBar" This reverts commit ea585d567bf0970c57e31846da044295d80774ba. --- src/gui/widgets/qmenubar.cpp | 2 +- src/gui/widgets/qmenubarimpl.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index a968404..357c0fa 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -441,7 +441,7 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const QSize sz; //calc what I think the size is.. - if (action->isSeparator()) { + i f(action->isSeparator()) { if (style->styleHint(QStyle::SH_DrawMenuBarSeparator, 0, q)) separator = i; continue; //we don't really position these! diff --git a/src/gui/widgets/qmenubarimpl.cpp b/src/gui/widgets/qmenubarimpl.cpp index db10c72..d402507 100644 --- a/src/gui/widgets/qmenubarimpl.cpp +++ b/src/gui/widgets/qmenubarimpl.cpp @@ -120,10 +120,12 @@ void QMenuBarImpl::actionEvent(QActionEvent *e) void QMenuBarImpl::handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow) { +#ifdef Q_WS_X11 Q_UNUSED(oldParent) Q_UNUSED(newParent) Q_UNUSED(oldWindow) Q_UNUSED(newWindow) +#endif #ifdef Q_WS_MAC if (isNativeMenuBar() && !macWidgetHasNativeMenubar(newParent)) { -- cgit v0.12 From c6514537a8568050f5812a2b55fcf47a3ec2fce1 Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Thu, 14 Apr 2011 14:58:25 +0200 Subject: Reverting merge request 916 Revert "Introduce menubar plugin system" This reverts commits 56c3de426d97ab7c8fb..f7b60fffb673b182e63 --- src/gui/widgets/qabstractmenubarimpl_p.cpp | 44 ++++++++++ src/gui/widgets/qabstractmenubarimpl_p.h | 104 +++++++++++++++++++++++ src/gui/widgets/qabstractmenubarinterface_p.h | 116 -------------------------- src/gui/widgets/qmenubar.cpp | 9 +- src/gui/widgets/qmenubar_p.h | 4 +- src/gui/widgets/qmenubarimpl.cpp | 34 ++------ src/gui/widgets/qmenubarimpl_p.h | 8 +- src/gui/widgets/widgets.pri | 3 +- 8 files changed, 167 insertions(+), 155 deletions(-) create mode 100644 src/gui/widgets/qabstractmenubarimpl_p.cpp create mode 100644 src/gui/widgets/qabstractmenubarimpl_p.h delete mode 100644 src/gui/widgets/qabstractmenubarinterface_p.h diff --git a/src/gui/widgets/qabstractmenubarimpl_p.cpp b/src/gui/widgets/qabstractmenubarimpl_p.cpp new file mode 100644 index 0000000..bc16030 --- /dev/null +++ b/src/gui/widgets/qabstractmenubarimpl_p.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include + +QAbstractMenuBarImpl::~QAbstractMenuBarImpl() +{} diff --git a/src/gui/widgets/qabstractmenubarimpl_p.h b/src/gui/widgets/qabstractmenubarimpl_p.h new file mode 100644 index 0000000..d001008 --- /dev/null +++ b/src/gui/widgets/qabstractmenubarimpl_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QABSTRACTMENUBARIMPL_P_H +#define QABSTRACTMENUBARIMPL_P_H + +#include + +#ifndef QT_NO_MENUBAR + +QT_BEGIN_NAMESPACE + +class QAction; +class QActionEvent; +class QEvent; +class QMenuBar; +class QObject; +class QWidget; + +/** + * The platform-specific implementation of a menubar + */ +class Q_GUI_EXPORT QAbstractMenuBarImpl +{ +public: + virtual ~QAbstractMenuBarImpl(); + + // QMenuBarPrivate::init() + virtual void init(QMenuBar *) = 0; + + // QMenuBar::setVisible() + virtual bool allowSetVisible() const = 0; + + virtual void actionEvent(QActionEvent *) = 0; + + // QMenuBar::handleReparent() + virtual void handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow) = 0; + + // QMenuBarPrivate::updateGeometries() + // QMenuBar::minimumSizeHint() + // QMenuBar::sizeHint() + // QMenuBar::heightForWidth() + virtual bool allowCornerWidgets() const = 0; + + // QMenuBar::_q_internalShortcutActivated() + virtual void popupAction(QAction*) = 0; + + // QMenuBar::setNativeMenuBar() + virtual void setNativeMenuBar(bool) = 0; + + virtual bool isNativeMenuBar() const = 0; + + /** + * Return true if the native menubar is capable of listening to the + * shortcut keys. If false is returned, QMenuBar will trigger actions on + * shortcut itself. + */ + virtual bool shortcutsHandledByNativeMenuBar() const = 0; + + virtual bool menuBarEventFilter(QObject *, QEvent *event) = 0; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_MENUBAR + +#endif // QABSTRACTMENUBARIMPL_P_H diff --git a/src/gui/widgets/qabstractmenubarinterface_p.h b/src/gui/widgets/qabstractmenubarinterface_p.h deleted file mode 100644 index a014bc1..0000000 --- a/src/gui/widgets/qabstractmenubarinterface_p.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QABSTRACTMENUBARINTERFACE_P_H -#define QABSTRACTMENUBARINTERFACE_P_H - -#include -#include -#include - -#ifndef QT_NO_MENUBAR - -QT_BEGIN_NAMESPACE - -class QAction; -class QActionEvent; -class QEvent; -class QMenuBar; -class QObject; -class QWidget; - -class QAbstractMenuBarInterface; - -struct QMenuBarImplFactoryInterface : public QFactoryInterface -{ - virtual QAbstractMenuBarInterface* createImpl() = 0; -}; - -#define QMenuBarImplFactoryInterface_iid "com.nokia.qt.QMenuBarImplFactoryInterface" -Q_DECLARE_INTERFACE(QMenuBarImplFactoryInterface, QMenuBarImplFactoryInterface_iid) - -/** - * The platform-specific implementation of a menubar - */ -class QAbstractMenuBarInterface -{ -public: - QAbstractMenuBarInterface() {} - virtual ~QAbstractMenuBarInterface() {} - - // QMenuBarPrivate::init() - virtual void init(QMenuBar *) = 0; - - virtual void setVisible(bool visible) = 0; - - virtual void actionEvent(QActionEvent *) = 0; - - // QMenuBar::handleReparent() - virtual void handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow) = 0; - - // QMenuBarPrivate::updateGeometries() - // QMenuBar::minimumSizeHint() - // QMenuBar::sizeHint() - // QMenuBar::heightForWidth() - virtual bool allowCornerWidgets() const = 0; - - // QMenuBar::_q_internalShortcutActivated() - virtual void popupAction(QAction*) = 0; - - // QMenuBar::setNativeMenuBar() - virtual void setNativeMenuBar(bool) = 0; - - virtual bool isNativeMenuBar() const = 0; - - /** - * Return true if the native menubar is capable of listening to the - * shortcut keys. If false is returned, QMenuBar will trigger actions on - * shortcut itself. - */ - virtual bool shortcutsHandledByNativeMenuBar() const = 0; - - virtual bool menuBarEventFilter(QObject *, QEvent *event) = 0; -}; - -QT_END_NAMESPACE - -#endif // QT_NO_MENUBAR - -#endif // QABSTRACTMENUBARINTERFACE_P_H diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index 357c0fa..4a31132 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -55,7 +55,6 @@ #include #include #include -#include #ifndef QT_NO_MENUBAR @@ -729,8 +728,7 @@ void QMenuBarPrivate::init() Q_Q(QMenuBar); q->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); q->setAttribute(Qt::WA_CustomWhatsThis); - - impl = qt_guiMenuBarImplFactory()->createImpl(); + impl = new QMenuBarImpl; impl->init(q); q->setBackgroundRole(QPalette::Button); @@ -1055,7 +1053,10 @@ void QMenuBar::paintEvent(QPaintEvent *e) void QMenuBar::setVisible(bool visible) { Q_D(QMenuBar); - d->impl->setVisible(visible); + if (!d->impl->allowSetVisible()) { + return; + } + QWidget::setVisible(visible); } /*! diff --git a/src/gui/widgets/qmenubar_p.h b/src/gui/widgets/qmenubar_p.h index 427cd30..b49e039 100644 --- a/src/gui/widgets/qmenubar_p.h +++ b/src/gui/widgets/qmenubar_p.h @@ -61,7 +61,7 @@ #include "qguifunctions_wince.h" #endif -#include "qabstractmenubarinterface_p.h" +#include "qabstractmenubarimpl_p.h" #ifndef QT_NO_MENUBAR #ifdef Q_WS_S60 @@ -160,7 +160,7 @@ public: #ifdef QT3_SUPPORT bool doAutoResize; #endif - QAbstractMenuBarInterface *impl; + QAbstractMenuBarImpl *impl; #ifdef QT_SOFTKEYS_ENABLED QAction *menuBarAction; #endif diff --git a/src/gui/widgets/qmenubarimpl.cpp b/src/gui/widgets/qmenubarimpl.cpp index d402507..cbe9198 100644 --- a/src/gui/widgets/qmenubarimpl.cpp +++ b/src/gui/widgets/qmenubarimpl.cpp @@ -49,8 +49,6 @@ #include "qmenu.h" #include "qmenubar.h" -#include - QT_BEGIN_NAMESPACE QMenuBarImpl::~QMenuBarImpl() @@ -90,16 +88,20 @@ void QMenuBarImpl::init(QMenuBar *_menuBar) #endif } -void QMenuBarImpl::setVisible(bool visible) +bool QMenuBarImpl::allowSetVisible() const { #if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) + // FIXME: Port this to a setVisible() method + /* if (isNativeMenuBar()) { if (!visible) - menuBar->QWidget::setVisible(false); + QWidget::setVisible(false); return; } + */ + return !isNativeMenuBar(); #endif - menuBar->QWidget::setVisible(visible); + return true; } void QMenuBarImpl::actionEvent(QActionEvent *e) @@ -237,28 +239,6 @@ bool QMenuBarImpl::menuBarEventFilter(QObject *, QEvent *) return false; } -struct QMenuBarImplFactory : public QMenuBarImplFactoryInterface -{ - QAbstractMenuBarInterface* createImpl() { return new QMenuBarImpl; } - virtual QStringList keys() const { return QStringList(); } -}; - -QMenuBarImplFactoryInterface *qt_guiMenuBarImplFactory() -{ - static QMenuBarImplFactoryInterface *factory = 0; - if (!factory) { -#ifndef QT_NO_LIBRARY - QFactoryLoader loader(QMenuBarImplFactoryInterface_iid, QLatin1String("/menubar")); - factory = qobject_cast(loader.instance(QLatin1String("default"))); -#endif // QT_NO_LIBRARY - if (!factory) { - static QMenuBarImplFactory def; - factory = &def; - } - } - return factory; -} - QT_END_NAMESPACE #endif // QT_NO_MENUBAR diff --git a/src/gui/widgets/qmenubarimpl_p.h b/src/gui/widgets/qmenubarimpl_p.h index 749c395..c4ab2df 100644 --- a/src/gui/widgets/qmenubarimpl_p.h +++ b/src/gui/widgets/qmenubarimpl_p.h @@ -44,20 +44,20 @@ #ifndef QT_NO_MENUBAR -#include "qabstractmenubarinterface_p.h" +#include "qabstractmenubarimpl_p.h" QT_BEGIN_NAMESPACE class QMenuBar; -class QMenuBarImpl : public QAbstractMenuBarInterface +class QMenuBarImpl : public QAbstractMenuBarImpl { public: ~QMenuBarImpl(); virtual void init(QMenuBar *); - virtual void setVisible(bool visible); + virtual bool allowSetVisible() const; virtual void actionEvent(QActionEvent *e); @@ -176,8 +176,6 @@ private: #endif }; -QMenuBarImplFactoryInterface *qt_guiMenuBarImplFactory(); - QT_END_NAMESPACE #endif // QT_NO_MENUBAR diff --git a/src/gui/widgets/widgets.pri b/src/gui/widgets/widgets.pri index 97d23f7..e5d6890 100644 --- a/src/gui/widgets/widgets.pri +++ b/src/gui/widgets/widgets.pri @@ -4,7 +4,7 @@ HEADERS += \ widgets/qbuttongroup.h \ widgets/qabstractbutton.h \ widgets/qabstractbutton_p.h \ - widgets/qabstractmenubarinterface_p.h \ + widgets/qabstractmenubarimpl_p.h \ widgets/qabstractslider.h \ widgets/qabstractslider_p.h \ widgets/qabstractspinbox.h \ @@ -85,6 +85,7 @@ HEADERS += \ widgets/qprintpreviewwidget.h SOURCES += \ widgets/qabstractbutton.cpp \ + widgets/qabstractmenubarimpl_p.cpp \ widgets/qabstractslider.cpp \ widgets/qabstractspinbox.cpp \ widgets/qcalendarwidget.cpp \ -- cgit v0.12 From bc16ebdb7aeff70fe8149297183636ea7fd14ed1 Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Thu, 14 Apr 2011 15:30:34 +0200 Subject: Fix licence headers again for MR 900 See commit b00089261eafbdf5f92ed94d7fb20b402bfcaeb2 Reviewed-by: Gabriel de Dietrich --- .../code/src_gui_itemviews_qidentityproxymodel.cpp | 4 +--- src/gui/itemviews/qidentityproxymodel.cpp | 14 +++++++++----- src/gui/itemviews/qidentityproxymodel.h | 13 +++++++++---- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp b/doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp index 8bd6520..6bf6c89 100644 --- a/doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp +++ b/doc/src/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp @@ -1,8 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2011 Klarälvdalens Datakonsult AB, -** a KDAB Group company, info@kdab.com, -** author Stephen Kelly +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** diff --git a/src/gui/itemviews/qidentityproxymodel.cpp b/src/gui/itemviews/qidentityproxymodel.cpp index fcc0504..60f7d98 100644 --- a/src/gui/itemviews/qidentityproxymodel.cpp +++ b/src/gui/itemviews/qidentityproxymodel.cpp @@ -1,13 +1,18 @@ /**************************************************************************** ** -** Copyright (C) 2011 Klarälvdalens Datakonsult AB, -** a KDAB Group company, info@kdab.com, -** author Stephen Kelly +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly ** All rights reserved. -** Contact: Nokia Corporation (info@qt.nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software @@ -34,7 +39,6 @@ ** ****************************************************************************/ - #include "qidentityproxymodel.h" #ifndef QT_NO_IDENTITYPROXYMODEL diff --git a/src/gui/itemviews/qidentityproxymodel.h b/src/gui/itemviews/qidentityproxymodel.h index 9845533..4b3176a 100644 --- a/src/gui/itemviews/qidentityproxymodel.h +++ b/src/gui/itemviews/qidentityproxymodel.h @@ -1,13 +1,18 @@ /**************************************************************************** ** -** Copyright (C) 2011 Klarälvdalens Datakonsult AB, -** a KDAB Group company, info@kdab.com, -** author Stephen Kelly +** Copyright (C) 2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Stephen Kelly ** All rights reserved. -** Contact: Nokia Corporation (info@qt.nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software -- cgit v0.12 From 7f921ea08c296e7451a44a1dae15350ae183ea20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Thu, 14 Apr 2011 18:00:42 +0200 Subject: Compile fix in qdrawhelper_sse2.cpp for MSVC 2005. --- src/gui/painting/qdrawhelper_sse2.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index c6bd339..affc6cc 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -523,7 +523,12 @@ public: static inline Int32x4 v_toInt(Float32x4 x) { return _mm_cvttps_epi32(x); } + // pre-VS 2008 doesn't have cast intrinsics, whereas 2008 and later requires it +#if defined(Q_CC_MSVC) && _MSC_VER < 1500 + static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return (__m128i)_mm_cmpgt_ps(a, b); } +#else static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return _mm_castps_si128(_mm_cmpgt_ps(a, b)); } +#endif }; const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, -- cgit v0.12 From 45c60ceac3d5a401543d7d56a44d1f9227464431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Fri, 15 Apr 2011 09:12:07 +0200 Subject: Another attempt at fixing the MSVC2005 build. Apparently direct casting is illegal there too, even though they don't have the cast operators. Reviewed-by: Kim --- src/gui/painting/qdrawhelper_sse2.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index affc6cc..be6dc91 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -525,7 +525,12 @@ public: // pre-VS 2008 doesn't have cast intrinsics, whereas 2008 and later requires it #if defined(Q_CC_MSVC) && _MSC_VER < 1500 - static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return (__m128i)_mm_cmpgt_ps(a, b); } + static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) + { + union Convert { Int32x4 vi; Float32x4 vf; } convert; + convert.vf = _mm_cmpgt_ps(a, b); + return convert.vi; + } #else static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return _mm_castps_si128(_mm_cmpgt_ps(a, b)); } #endif -- cgit v0.12 From 443d5b17619002cd6bb428198c453271a01accab Mon Sep 17 00:00:00 2001 From: Gabriel de Dietrich Date: Fri, 15 Apr 2011 12:04:05 +0200 Subject: Totally kill MR 916 ... the hard way. Reviewed-by: Trust me --- src/gui/widgets/qabstractmenubarimpl_p.cpp | 44 --- src/gui/widgets/qabstractmenubarimpl_p.h | 104 ------- src/gui/widgets/qmenu_mac.mm | 4 +- src/gui/widgets/qmenu_p.h | 6 +- src/gui/widgets/qmenu_symbian.cpp | 4 +- src/gui/widgets/qmenu_wince.cpp | 4 +- src/gui/widgets/qmenubar.cpp | 439 +++++++++++++++++------------ src/gui/widgets/qmenubar_p.h | 129 ++++++++- src/gui/widgets/qmenubarimpl.cpp | 244 ---------------- src/gui/widgets/qmenubarimpl_p.h | 183 ------------ src/gui/widgets/widgets.pri | 3 - 11 files changed, 385 insertions(+), 779 deletions(-) delete mode 100644 src/gui/widgets/qabstractmenubarimpl_p.cpp delete mode 100644 src/gui/widgets/qabstractmenubarimpl_p.h delete mode 100644 src/gui/widgets/qmenubarimpl.cpp delete mode 100644 src/gui/widgets/qmenubarimpl_p.h diff --git a/src/gui/widgets/qabstractmenubarimpl_p.cpp b/src/gui/widgets/qabstractmenubarimpl_p.cpp deleted file mode 100644 index bc16030..0000000 --- a/src/gui/widgets/qabstractmenubarimpl_p.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include - -QAbstractMenuBarImpl::~QAbstractMenuBarImpl() -{} diff --git a/src/gui/widgets/qabstractmenubarimpl_p.h b/src/gui/widgets/qabstractmenubarimpl_p.h deleted file mode 100644 index d001008..0000000 --- a/src/gui/widgets/qabstractmenubarimpl_p.h +++ /dev/null @@ -1,104 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#ifndef QABSTRACTMENUBARIMPL_P_H -#define QABSTRACTMENUBARIMPL_P_H - -#include - -#ifndef QT_NO_MENUBAR - -QT_BEGIN_NAMESPACE - -class QAction; -class QActionEvent; -class QEvent; -class QMenuBar; -class QObject; -class QWidget; - -/** - * The platform-specific implementation of a menubar - */ -class Q_GUI_EXPORT QAbstractMenuBarImpl -{ -public: - virtual ~QAbstractMenuBarImpl(); - - // QMenuBarPrivate::init() - virtual void init(QMenuBar *) = 0; - - // QMenuBar::setVisible() - virtual bool allowSetVisible() const = 0; - - virtual void actionEvent(QActionEvent *) = 0; - - // QMenuBar::handleReparent() - virtual void handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow) = 0; - - // QMenuBarPrivate::updateGeometries() - // QMenuBar::minimumSizeHint() - // QMenuBar::sizeHint() - // QMenuBar::heightForWidth() - virtual bool allowCornerWidgets() const = 0; - - // QMenuBar::_q_internalShortcutActivated() - virtual void popupAction(QAction*) = 0; - - // QMenuBar::setNativeMenuBar() - virtual void setNativeMenuBar(bool) = 0; - - virtual bool isNativeMenuBar() const = 0; - - /** - * Return true if the native menubar is capable of listening to the - * shortcut keys. If false is returned, QMenuBar will trigger actions on - * shortcut itself. - */ - virtual bool shortcutsHandledByNativeMenuBar() const = 0; - - virtual bool menuBarEventFilter(QObject *, QEvent *event) = 0; -}; - -QT_END_NAMESPACE - -#endif // QT_NO_MENUBAR - -#endif // QABSTRACTMENUBARIMPL_P_H diff --git a/src/gui/widgets/qmenu_mac.mm b/src/gui/widgets/qmenu_mac.mm index f780ee7..2977558 100644 --- a/src/gui/widgets/qmenu_mac.mm +++ b/src/gui/widgets/qmenu_mac.mm @@ -1639,7 +1639,7 @@ QMenuBarPrivate::QMacMenuBarPrivate::~QMacMenuBarPrivate() } void -QMenuBarPrivate::QMacMenuBarPrivate::addAction(QAction *a, QAction *before) +QMenuBarPrivate::QMacMenuBarPrivate::addAction(QAction *a, QMacMenuAction *before) { if (a->isSeparator() || !menu) return; @@ -1649,7 +1649,7 @@ QMenuBarPrivate::QMacMenuBarPrivate::addAction(QAction *a, QAction *before) #ifndef QT_MAC_USE_COCOA action->command = qt_mac_menu_static_cmd_id++; #endif - addAction(action, findAction(before)); + addAction(action, before); } void diff --git a/src/gui/widgets/qmenu_p.h b/src/gui/widgets/qmenu_p.h index 9fd55ca..005ce1d 100644 --- a/src/gui/widgets/qmenu_p.h +++ b/src/gui/widgets/qmenu_p.h @@ -154,9 +154,6 @@ public: #endif scroll(0), eventLoop(0), tearoff(0), tornoff(0), tearoffHighlighted(0), hasCheckableItems(0), sloppyAction(0), doChildEffects(false) -#ifdef QT3_SUPPORT - ,emitHighlighted(false) -#endif #ifdef Q_WS_MAC ,mac_menu(0) #endif @@ -166,6 +163,9 @@ public: #ifdef Q_WS_S60 ,symbian_menu(0) #endif +#ifdef QT3_SUPPORT + ,emitHighlighted(false) +#endif { } ~QMenuPrivate() { diff --git a/src/gui/widgets/qmenu_symbian.cpp b/src/gui/widgets/qmenu_symbian.cpp index 12c6c6e..d614bb8 100644 --- a/src/gui/widgets/qmenu_symbian.cpp +++ b/src/gui/widgets/qmenu_symbian.cpp @@ -398,12 +398,12 @@ void QMenuPrivate::QSymbianMenuPrivate::rebuild(bool) { } -void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QAction *a, QAction *before) +void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QAction *a, QSymbianMenuAction *before) { QSymbianMenuAction *action = new QSymbianMenuAction; action->action = a; action->command = qt_symbian_menu_static_cmd_id++; - addAction(action, findAction(before)); + addAction(action, before); } void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before) diff --git a/src/gui/widgets/qmenu_wince.cpp b/src/gui/widgets/qmenu_wince.cpp index 2210409..86a78ad 100644 --- a/src/gui/widgets/qmenu_wince.cpp +++ b/src/gui/widgets/qmenu_wince.cpp @@ -504,12 +504,12 @@ void QMenuPrivate::QWceMenuPrivate::removeAction(QWceMenuAction *action) rebuild(); } -void QMenuBarPrivate::QWceMenuBarPrivate::addAction(QAction *a, QAction *before) +void QMenuBarPrivate::QWceMenuBarPrivate::addAction(QAction *a, QWceMenuAction *before) { QWceMenuAction *action = new QWceMenuAction; action->action = a; action->command = qt_wce_menu_static_cmd_id++; - addAction(action, findAction(before)); + addAction(action, before); } void QMenuBarPrivate::QWceMenuBarPrivate::addAction(QWceMenuAction *action, QWceMenuAction *before) diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index 4a31132..5bfac9a 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -63,10 +63,9 @@ #include #endif -#include "qdebug.h" #include "qmenu_p.h" #include "qmenubar_p.h" -#include "qmenubarimpl_p.h" +#include "qdebug.h" #ifdef Q_WS_WINCE extern bool qt_wince_is_mobile(); //defined in qguifunctions_wce.cpp @@ -121,8 +120,8 @@ QSize QMenuBarExtension::sizeHint() const */ QAction *QMenuBarPrivate::actionAt(QPoint p) const { - for (int i = 0; i < actions.size(); ++i) { - if (actionRect(actions.at(i)).contains(p)) + for(int i = 0; i < actions.size(); ++i) { + if(actionRect(actions.at(i)).contains(p)) return actions.at(i); } return 0; @@ -170,12 +169,11 @@ bool QMenuBarPrivate::isVisible(QAction *action) void QMenuBarPrivate::updateGeometries() { Q_Q(QMenuBar); - if (!itemsDirty) + if(!itemsDirty) return; int q_width = q->width()-(q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q)*2); int q_start = -1; - - if (impl->allowCornerWidgets() && (leftWidget || rightWidget)) { + if(leftWidget || rightWidget) { int vmargin = q->style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, q) + q->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, q); int hmargin = q->style()->pixelMetric(QStyle::PM_MenuBarHMargin, 0, q) @@ -197,8 +195,16 @@ void QMenuBarPrivate::updateGeometries() } } +#ifdef Q_WS_MAC + if(q->isNativeMenuBar()) {//nothing to see here folks, move along.. + itemsDirty = false; + return; + } +#endif + calcActionRects(q_width, q_start); + currentAction = 0; #ifndef QT_NO_SHORTCUT - if (!impl->shortcutsHandledByNativeMenuBar() && itemsDirty) { + if(itemsDirty) { for(int j = 0; j < shortcutIndexMap.size(); ++j) q->releaseShortcut(shortcutIndexMap.value(j)); shortcutIndexMap.resize(0); // faster than clear @@ -206,12 +212,6 @@ void QMenuBarPrivate::updateGeometries() shortcutIndexMap.append(q->grabShortcut(QKeySequence::mnemonic(actions.at(i)->text()))); } #endif - if (q->isNativeMenuBar()) {//nothing to see here folks, move along.. - itemsDirty = false; - return; - } - calcActionRects(q_width, q_start); - currentAction = 0; itemsDirty = false; hiddenActions.clear(); @@ -281,7 +281,7 @@ QRect QMenuBarPrivate::actionRect(QAction *act) const void QMenuBarPrivate::focusFirstAction() { - if (!currentAction) { + if(!currentAction) { updateGeometries(); int index = 0; while (index < actions.count() && actionRects.at(index).isNull()) ++index; @@ -298,16 +298,16 @@ void QMenuBarPrivate::setKeyboardMode(bool b) return; } keyboardState = b; - if (b) { + if(b) { QWidget *fw = QApplication::focusWidget(); if (fw != q) keyboardFocusWidget = fw; focusFirstAction(); q->setFocus(Qt::MenuBarFocusReason); } else { - if (!popupState) + if(!popupState) setCurrentAction(0); - if (keyboardFocusWidget) { + if(keyboardFocusWidget) { if (QApplication::focusWidget() == q) keyboardFocusWidget->setFocus(Qt::MenuBarFocusReason); keyboardFocusWidget = 0; @@ -319,7 +319,7 @@ void QMenuBarPrivate::setKeyboardMode(bool b) void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) { Q_Q(QMenuBar); - if (!action || !action->menu() || closePopupMode) + if(!action || !action->menu() || closePopupMode) return; popupState = true; if (action->isEnabled() && action->menu()->isEnabled()) { @@ -359,10 +359,10 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) pos.rx() += actionWidth; } - if (!defaultPopDown || (fitUp && !fitDown)) + if(!defaultPopDown || (fitUp && !fitDown)) pos.setY(qMax(screenRect.y(), q->mapToGlobal(QPoint(0, adjustedActionRect.top()-popup_size.height())).y())); activeMenu->popup(pos); - if (activateFirst) + if(activateFirst) activeMenu->d_func()->setFirstActionActive(); } q->update(actionRect(action)); @@ -370,7 +370,7 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst) void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activateFirst) { - if (currentAction == action && popup == popupState) + if(currentAction == action && popup == popupState) return; autoReleaseTimer.stop(); @@ -378,7 +378,7 @@ void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activat doChildEffects = (popup && !activeMenu); Q_Q(QMenuBar); QWidget *fw = 0; - if (QMenu *menu = activeMenu) { + if(QMenu *menu = activeMenu) { activeMenu = 0; if (popup) { fw = q->window()->focusWidget(); @@ -387,7 +387,7 @@ void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activat menu->hide(); } - if (currentAction) + if(currentAction) q->update(actionRect(currentAction)); popupState = popup; @@ -397,7 +397,7 @@ void QMenuBarPrivate::setCurrentAction(QAction *action, bool popup, bool activat currentAction = action; if (action) { activateAction(action, QAction::Hover); - if (popup) + if(popup) popupAction(action, activateFirst); q->update(actionRect(action)); #ifndef QT_NO_STATUSTIP @@ -415,7 +415,7 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const { Q_Q(const QMenuBar); - if (!itemsDirty) + if(!itemsDirty) return; //let's reinitialize the buffer @@ -434,13 +434,13 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const icone = style->pixelMetric(QStyle::PM_SmallIconSize, 0, q); for(int i = 0; i < actions.count(); i++) { QAction *action = actions.at(i); - if (!action->isVisible()) + if(!action->isVisible()) continue; QSize sz; //calc what I think the size is.. - i f(action->isSeparator()) { + if(action->isSeparator()) { if (style->styleHint(QStyle::SH_DrawMenuBarSeparator, 0, q)) separator = i; continue; //we don't really position these! @@ -459,10 +459,10 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const q->initStyleOption(&opt, action); sz = q->style()->sizeFromContents(QStyle::CT_MenuBarItem, &opt, sz, q); - if (!sz.isEmpty()) { + if(!sz.isEmpty()) { { //update the separator state int iWidth = sz.width() + itemSpacing; - if (separator == -1) + if(separator == -1) separator_start += iWidth; else separator_len += iWidth; @@ -487,9 +487,9 @@ void QMenuBarPrivate::calcActionRects(int max_width, int start) const rect.setHeight(max_item_height); //move - if (separator != -1 && i >= separator) { //after the separator + if(separator != -1 && i >= separator) { //after the separator int left = (max_width - separator_len - hmargin - itemSpacing) + (x - separator_start - hmargin); - if (left < separator_start) { //wrap + if(left < separator_start) { //wrap separator_start = x = hmargin; y += max_item_height; } @@ -516,9 +516,9 @@ void QMenuBarPrivate::activateAction(QAction *action, QAction::ActionEvent actio if (action_e == QAction::Hover) action->showStatusText(q); -// if (action_e == QAction::Trigger) +// if(action_e == QAction::Trigger) // emit q->activated(action); -// else if (action_e == QAction::Hover) +// else if(action_e == QAction::Hover) // emit q->highlighted(action); } @@ -728,9 +728,21 @@ void QMenuBarPrivate::init() Q_Q(QMenuBar); q->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); q->setAttribute(Qt::WA_CustomWhatsThis); - impl = new QMenuBarImpl; - impl->init(q); - +#ifdef Q_WS_MAC + macCreateMenuBar(q->parentWidget()); + if(mac_menubar) + q->hide(); +#endif +#ifdef Q_WS_WINCE + if (qt_wince_is_mobile()) { + wceCreateMenuBar(q->parentWidget()); + if(wce_menubar) + q->hide(); + } + else { + QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true); + } +#endif q->setBackgroundRole(QPalette::Button); oldWindow = oldParent = 0; #ifdef QT3_SUPPORT @@ -739,9 +751,6 @@ void QMenuBarPrivate::init() #ifdef QT_SOFTKEYS_ENABLED menuBarAction = 0; #endif - cornerWidgetToolBar = 0; - cornerWidgetContainer = 0; - handleReparent(); q->setMouseTracking(q->style()->styleHint(QStyle::SH_MenuBar_MouseTracking, 0, q)); @@ -799,8 +808,19 @@ QMenuBar::QMenuBar(QWidget *parent, const char *name) : QWidget(*new QMenuBarPri */ QMenuBar::~QMenuBar() { +#ifdef Q_WS_MAC + Q_D(QMenuBar); + d->macDestroyMenuBar(); +#endif +#ifdef Q_WS_WINCE + Q_D(QMenuBar); + if (qt_wince_is_mobile()) + d->wceDestroyMenuBar(); +#endif +#ifdef Q_WS_S60 Q_D(QMenuBar); - delete d->cornerWidgetToolBar; + d->symbianDestroyMenuBar(); +#endif } /*! @@ -1009,7 +1029,7 @@ void QMenuBar::paintEvent(QPaintEvent *e) QRect adjustedActionRect = d->actionRect(action); if (adjustedActionRect.isEmpty() || !d->isVisible(action)) continue; - if (!e->rect().intersects(adjustedActionRect)) + if(!e->rect().intersects(adjustedActionRect)) continue; emptyArea -= adjustedActionRect; @@ -1020,7 +1040,7 @@ void QMenuBar::paintEvent(QPaintEvent *e) style()->drawControl(QStyle::CE_MenuBarItem, &opt, &p, this); } //draw border - if (int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this)) { + if(int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this)) { QRegion borderReg; borderReg += QRect(0, 0, fw, height()); //left borderReg += QRect(width()-fw, 0, fw, height()); //right @@ -1052,10 +1072,13 @@ void QMenuBar::paintEvent(QPaintEvent *e) */ void QMenuBar::setVisible(bool visible) { - Q_D(QMenuBar); - if (!d->impl->allowSetVisible()) { +#if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) + if (isNativeMenuBar()) { + if (!visible) + QWidget::setVisible(false); return; } +#endif QWidget::setVisible(visible); } @@ -1065,7 +1088,7 @@ void QMenuBar::setVisible(bool visible) void QMenuBar::mousePressEvent(QMouseEvent *e) { Q_D(QMenuBar); - if (e->button() != Qt::LeftButton) + if(e->button() != Qt::LeftButton) return; d->mouseDown = true; @@ -1080,13 +1103,13 @@ void QMenuBar::mousePressEvent(QMouseEvent *e) return; } - if (d->currentAction == action && d->popupState) { - if (QMenu *menu = d->activeMenu) { + if(d->currentAction == action && d->popupState) { + if(QMenu *menu = d->activeMenu) { d->activeMenu = 0; menu->hide(); } #ifdef Q_WS_WIN - if ((d->closePopupMode = style()->styleHint(QStyle::SH_MenuBar_DismissOnSecondClick))) + if((d->closePopupMode = style()->styleHint(QStyle::SH_MenuBar_DismissOnSecondClick))) update(d->actionRect(action)); #endif } else { @@ -1100,16 +1123,16 @@ void QMenuBar::mousePressEvent(QMouseEvent *e) void QMenuBar::mouseReleaseEvent(QMouseEvent *e) { Q_D(QMenuBar); - if (e->button() != Qt::LeftButton || !d->mouseDown) + if(e->button() != Qt::LeftButton || !d->mouseDown) return; d->mouseDown = false; QAction *action = d->actionAt(e->pos()); - if ((d->closePopupMode && action == d->currentAction) || !action || !action->menu()) { + if((d->closePopupMode && action == d->currentAction) || !action || !action->menu()) { //we set the current action before activating //so that we let the leave event set the current back to 0 d->setCurrentAction(action, false); - if (action) + if(action) d->activateAction(action, QAction::Trigger); } d->closePopupMode = 0; @@ -1123,15 +1146,15 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) Q_D(QMenuBar); d->updateGeometries(); int key = e->key(); - if (isRightToLeft()) { // in reverse mode open/close key for submenues are reversed - if (key == Qt::Key_Left) + if(isRightToLeft()) { // in reverse mode open/close key for submenues are reversed + if(key == Qt::Key_Left) key = Qt::Key_Right; - else if (key == Qt::Key_Right) + else if(key == Qt::Key_Right) key = Qt::Key_Left; } - if (key == Qt::Key_Tab) //means right + if(key == Qt::Key_Tab) //means right key = Qt::Key_Right; - else if (key == Qt::Key_Backtab) //means left + else if(key == Qt::Key_Backtab) //means left key = Qt::Key_Left; bool key_consumed = false; @@ -1141,11 +1164,11 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) case Qt::Key_Enter: case Qt::Key_Space: case Qt::Key_Return: { - if (!style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, this) || !d->currentAction) + if(!style()->styleHint(QStyle::SH_MenuBar_AltKeyNavigation, 0, this) || !d->currentAction) break; - if (d->currentAction->menu()) { + if(d->currentAction->menu()) { d->popupAction(d->currentAction, true); - } else if (key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Space) { + } else if(key == Qt::Key_Enter || key == Qt::Key_Return || key == Qt::Key_Space) { d->activateAction(d->currentAction, QAction::Trigger); d->setCurrentAction(d->currentAction, false); d->setKeyboardMode(false); @@ -1155,7 +1178,7 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) case Qt::Key_Right: case Qt::Key_Left: { - if (d->currentAction) { + if(d->currentAction) { int index = d->actions.indexOf(d->currentAction); if (QAction *nextAction = d->getNextAction(index, key == Qt::Key_Left ? -1 : +1)) { d->setCurrentAction(nextAction, d->popupState, true); @@ -1174,7 +1197,7 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) key_consumed = false; } - if (!key_consumed && + if(!key_consumed && (!e->modifiers() || (e->modifiers()&(Qt::MetaModifier|Qt::AltModifier))) && e->text().length()==1 && !d->popupState) { int clashCount = 0; @@ -1186,14 +1209,14 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) continue; QAction *act = d->actions.at(i); QString s = act->text(); - if (!s.isEmpty()) { + if(!s.isEmpty()) { int ampersand = s.indexOf(QLatin1Char('&')); - if (ampersand >= 0) { - if (s[ampersand+1].toUpper() == c) { + if(ampersand >= 0) { + if(s[ampersand+1].toUpper() == c) { clashCount++; - if (!first) + if(!first) first = act; - if (act == d->currentAction) + if(act == d->currentAction) currentSelected = act; else if (!firstAfterCurrent && currentSelected) firstAfterCurrent = act; @@ -1203,18 +1226,18 @@ void QMenuBar::keyPressEvent(QKeyEvent *e) } } QAction *next_action = 0; - if (clashCount >= 1) { - if (clashCount == 1 || !d->currentAction || (currentSelected && !firstAfterCurrent)) + if(clashCount >= 1) { + if(clashCount == 1 || !d->currentAction || (currentSelected && !firstAfterCurrent)) next_action = first; else next_action = firstAfterCurrent; } - if (next_action) { + if(next_action) { key_consumed = true; d->setCurrentAction(next_action, true, true); } } - if (key_consumed) + if(key_consumed) e->accept(); else e->ignore(); @@ -1240,7 +1263,7 @@ void QMenuBar::mouseMoveEvent(QMouseEvent *e) void QMenuBar::leaveEvent(QEvent *) { Q_D(QMenuBar); - if ((!hasFocus() && !d->popupState) || + if((!hasFocus() && !d->popupState) || (d->currentAction && d->currentAction->menu() == 0)) d->setCurrentAction(0); } @@ -1252,12 +1275,30 @@ void QMenuBar::actionEvent(QActionEvent *e) { Q_D(QMenuBar); d->itemsDirty = true; - d->impl->actionEvent(e); +#if defined (Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) + if (isNativeMenuBar()) { +#ifdef Q_WS_MAC + QMenuBarPrivate::QMacMenuBarPrivate *nativeMenuBar = d->mac_menubar; +#elif defined(Q_WS_S60) + QMenuBarPrivate::QSymbianMenuBarPrivate *nativeMenuBar = d->symbian_menubar; +#else + QMenuBarPrivate::QWceMenuBarPrivate *nativeMenuBar = d->wce_menubar; +#endif + if (!nativeMenuBar) + return; + if(e->type() == QEvent::ActionAdded) + nativeMenuBar->addAction(e->action(), nativeMenuBar->findAction(e->before())); + else if(e->type() == QEvent::ActionRemoved) + nativeMenuBar->removeAction(e->action()); + else if(e->type() == QEvent::ActionChanged) + nativeMenuBar->syncAction(e->action()); + } +#endif - if (e->type() == QEvent::ActionAdded) { + if(e->type() == QEvent::ActionAdded) { connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered())); connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered())); - } else if (e->type() == QEvent::ActionRemoved) { + } else if(e->type() == QEvent::ActionRemoved) { e->action()->disconnect(this); } if (isVisible()) { @@ -1272,7 +1313,7 @@ void QMenuBar::actionEvent(QActionEvent *e) void QMenuBar::focusInEvent(QFocusEvent *) { Q_D(QMenuBar); - if (d->keyboardState) + if(d->keyboardState) d->focusFirstAction(); } @@ -1282,7 +1323,7 @@ void QMenuBar::focusInEvent(QFocusEvent *) void QMenuBar::focusOutEvent(QFocusEvent *) { Q_D(QMenuBar); - if (!d->popupState) { + if(!d->popupState) { d->setCurrentAction(0); d->setKeyboardMode(false); } @@ -1328,10 +1369,55 @@ void QMenuBarPrivate::handleReparent() newWindow->installEventFilter(q); } - impl->handleReparent(oldParent, newParent, oldWindow, newWindow); - oldParent = newParent; oldWindow = newWindow; + +#ifdef Q_WS_MAC + if (q->isNativeMenuBar() && !macWidgetHasNativeMenubar(newParent)) { + // If the new parent got a native menubar from before, keep that + // menubar rather than replace it with this one (because a parents + // menubar has precedence over children menubars). + macDestroyMenuBar(); + macCreateMenuBar(newParent); + } +#endif + +#ifdef Q_WS_WINCE + if (qt_wince_is_mobile() && wce_menubar) + wce_menubar->rebuild(); +#endif +#ifdef Q_WS_S60 + + // Construct symbian_menubar when this code path is entered first time + // and when newParent != NULL + if (!symbian_menubar) + symbianCreateMenuBar(newParent); + + // Reparent and rebuild menubar when parent is changed + if (symbian_menubar) { + if (oldParent != newParent) + reparentMenuBar(oldParent, newParent); + q->hide(); + symbian_menubar->rebuild(); + } + +#ifdef QT_SOFTKEYS_ENABLED + // Constuct menuBarAction when this code path is entered first time + if (!menuBarAction) { + if (newParent) { + menuBarAction = QSoftKeyManager::createAction(QSoftKeyManager::MenuSoftKey, newParent); + newParent->addAction(menuBarAction); + } + } else { + // If reparenting i.e. we already have menuBarAction, remove it from old parent + // and add for a new parent + if (oldParent) + oldParent->removeAction(menuBarAction); + if (newParent) + newParent->addAction(menuBarAction); + } +#endif // QT_SOFTKEYS_ENABLED +#endif // Q_WS_S60 } #ifdef QT3_SUPPORT @@ -1372,10 +1458,10 @@ bool QMenuBar::autoGeometry() const void QMenuBar::changeEvent(QEvent *e) { Q_D(QMenuBar); - if (e->type() == QEvent::StyleChange) { + if(e->type() == QEvent::StyleChange) { d->itemsDirty = true; setMouseTracking(style()->styleHint(QStyle::SH_MenuBar_MouseTracking, 0, this)); - if (parentWidget()) + if(parentWidget()) resize(parentWidget()->width(), heightForWidth(parentWidget()->width())); d->updateGeometries(); } else if (e->type() == QEvent::ParentChange) { @@ -1404,12 +1490,12 @@ bool QMenuBar::event(QEvent *e) case QEvent::KeyPress: { QKeyEvent *ke = (QKeyEvent*)e; #if 0 - if (!d->keyboardState) { //all keypresses.. + if(!d->keyboardState) { //all keypresses.. d->setCurrentAction(0); return ; } #endif - if (ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) { + if(ke->key() == Qt::Key_Tab || ke->key() == Qt::Key_Backtab) { keyPressEvent(ke); return true; } @@ -1427,7 +1513,7 @@ bool QMenuBar::event(QEvent *e) #endif case QEvent::Show: #ifdef QT3_SUPPORT - if (QWidget *p = parentWidget()) { + if(QWidget *p = parentWidget()) { // If itemsDirty == true, updateGeometries sends the MenubarUpdated event. if (!d->itemsDirty) { QMenubarUpdatedEvent menubarUpdated(this); @@ -1449,7 +1535,7 @@ bool QMenuBar::event(QEvent *e) #ifdef QT3_SUPPORT case QEvent::Hide: { - if (QWidget *p = parentWidget()) { + if(QWidget *p = parentWidget()) { QMenubarUpdatedEvent menubarUpdated(this); QApplication::sendEvent(p, &menubarUpdated); } @@ -1480,9 +1566,6 @@ bool QMenuBar::event(QEvent *e) bool QMenuBar::eventFilter(QObject *object, QEvent *event) { Q_D(QMenuBar); - if (d->impl->menuBarEventFilter(object, event)) { - return true; - } if (object == parent() && object) { #ifdef QT3_SUPPORT if (d->doAutoResize && event->type() == QEvent::Resize) { @@ -1576,7 +1659,11 @@ QRect QMenuBar::actionGeometry(QAction *act) const QSize QMenuBar::minimumSizeHint() const { Q_D(const QMenuBar); +#if defined(Q_WS_MAC) || defined(Q_WS_WINCE) || defined(Q_WS_S60) const bool as_gui_menubar = !isNativeMenuBar(); +#else + const bool as_gui_menubar = true; +#endif ensurePolished(); QSize ret(0, 0); @@ -1585,7 +1672,7 @@ QSize QMenuBar::minimumSizeHint() const const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, this); int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this); int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, 0, this); - if (as_gui_menubar) { + if(as_gui_menubar) { int w = parentWidget() ? parentWidget()->width() : QApplication::desktop()->width(); d->calcActionRects(w - (2 * fw), 0); for (int i = 0; ret.isNull() && i < d->actions.count(); ++i) @@ -1595,21 +1682,19 @@ QSize QMenuBar::minimumSizeHint() const ret += QSize(2*fw + hmargin, 2*fw + vmargin); } int margin = 2*vmargin + 2*fw + spaceBelowMenuBar; - if (d->impl->allowCornerWidgets()) { - if (d->leftWidget) { - QSize sz = d->leftWidget->minimumSizeHint(); - ret.setWidth(ret.width() + sz.width()); - if (sz.height() + margin > ret.height()) - ret.setHeight(sz.height() + margin); - } - if (d->rightWidget) { - QSize sz = d->rightWidget->minimumSizeHint(); - ret.setWidth(ret.width() + sz.width()); - if (sz.height() + margin > ret.height()) - ret.setHeight(sz.height() + margin); - } - } - if (as_gui_menubar) { + if(d->leftWidget) { + QSize sz = d->leftWidget->minimumSizeHint(); + ret.setWidth(ret.width() + sz.width()); + if(sz.height() + margin > ret.height()) + ret.setHeight(sz.height() + margin); + } + if(d->rightWidget) { + QSize sz = d->rightWidget->minimumSizeHint(); + ret.setWidth(ret.width() + sz.width()); + if(sz.height() + margin > ret.height()) + ret.setHeight(sz.height() + margin); + } + if(as_gui_menubar) { QStyleOptionMenuItem opt; opt.rect = rect(); opt.menuRect = rect(); @@ -1630,7 +1715,12 @@ QSize QMenuBar::minimumSizeHint() const QSize QMenuBar::sizeHint() const { Q_D(const QMenuBar); +#if defined(Q_WS_MAC) || defined(Q_WS_WINCE) || defined(Q_WS_S60) const bool as_gui_menubar = !isNativeMenuBar(); +#else + const bool as_gui_menubar = true; +#endif + ensurePolished(); QSize ret(0, 0); @@ -1639,7 +1729,7 @@ QSize QMenuBar::sizeHint() const const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, this); int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this); int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, 0, this); - if (as_gui_menubar) { + if(as_gui_menubar) { const int w = parentWidget() ? parentWidget()->width() : QApplication::desktop()->width(); d->calcActionRects(w - (2 * fw), 0); for (int i = 0; i < d->actionRects.count(); ++i) { @@ -1651,21 +1741,19 @@ QSize QMenuBar::sizeHint() const ret += QSize(fw + hmargin, fw + vmargin); } int margin = 2*vmargin + 2*fw + spaceBelowMenuBar; - if (d->impl->allowCornerWidgets()) { - if (d->leftWidget) { - QSize sz = d->leftWidget->sizeHint(); - ret.setWidth(ret.width() + sz.width()); - if (sz.height() + margin > ret.height()) - ret.setHeight(sz.height() + margin); - } - if (d->rightWidget) { - QSize sz = d->rightWidget->sizeHint(); - ret.setWidth(ret.width() + sz.width()); - if (sz.height() + margin > ret.height()) - ret.setHeight(sz.height() + margin); - } - } - if (as_gui_menubar) { + if(d->leftWidget) { + QSize sz = d->leftWidget->sizeHint(); + ret.setWidth(ret.width() + sz.width()); + if(sz.height() + margin > ret.height()) + ret.setHeight(sz.height() + margin); + } + if(d->rightWidget) { + QSize sz = d->rightWidget->sizeHint(); + ret.setWidth(ret.width() + sz.width()); + if(sz.height() + margin > ret.height()) + ret.setHeight(sz.height() + margin); + } + if(as_gui_menubar) { QStyleOptionMenuItem opt; opt.rect = rect(); opt.menuRect = rect(); @@ -1686,14 +1774,18 @@ QSize QMenuBar::sizeHint() const int QMenuBar::heightForWidth(int) const { Q_D(const QMenuBar); +#if defined(Q_WS_MAC) || defined(Q_WS_WINCE) || defined(Q_WS_S60) const bool as_gui_menubar = !isNativeMenuBar(); +#else + const bool as_gui_menubar = true; +#endif const_cast(d)->updateGeometries(); int height = 0; const int vmargin = style()->pixelMetric(QStyle::PM_MenuBarVMargin, 0, this); int fw = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, 0, this); int spaceBelowMenuBar = style()->styleHint(QStyle::SH_MainWindow_SpaceBelowMenuBar, 0, this); - if (as_gui_menubar) { + if(as_gui_menubar) { for (int i = 0; i < d->actionRects.count(); ++i) height = qMax(height, d->actionRects.at(i).height()); if (height) //there is at least one non-null item @@ -1702,13 +1794,11 @@ int QMenuBar::heightForWidth(int) const height += 2*vmargin; } int margin = 2*vmargin + 2*fw + spaceBelowMenuBar; - if (d->impl->allowCornerWidgets()) { - if (d->leftWidget) - height = qMax(d->leftWidget->sizeHint().height() + margin, height); - if (d->rightWidget) - height = qMax(d->rightWidget->sizeHint().height() + margin, height); - } - if (as_gui_menubar) { + if(d->leftWidget) + height = qMax(d->leftWidget->sizeHint().height() + margin, height); + if(d->rightWidget) + height = qMax(d->rightWidget->sizeHint().height() + margin, height); + if(as_gui_menubar) { QStyleOptionMenuItem opt; opt.init(this); opt.menuRect = rect(); @@ -1727,11 +1817,7 @@ void QMenuBarPrivate::_q_internalShortcutActivated(int id) { Q_Q(QMenuBar); QAction *act = actions.at(id); - if (q->isNativeMenuBar()) { - impl->popupAction(act); - } else { - setCurrentAction(act, true, true); - } + setCurrentAction(act, true, true); if (act && !act->menu()) { activateAction(act, QAction::Trigger); //100 is the same as the default value in QPushButton::animateClick @@ -1752,37 +1838,6 @@ void QMenuBarPrivate::_q_updateLayout() } } -void QMenuBarPrivate::updateCornerWidgetToolBar() -{ - Q_Q(QMenuBar); - if (!cornerWidgetToolBar) { - QMainWindow *window = qobject_cast(q->window()); - if (!window) { - qWarning() << "Menubar parent is not a QMainWindow, not showing corner widgets"; - return; - } - cornerWidgetToolBar = window->addToolBar(QApplication::translate("QMenuBar", "Corner Toolbar")); - cornerWidgetToolBar->setObjectName(QLatin1String("CornerToolBar")); - cornerWidgetContainer = new QWidget; - cornerWidgetToolBar->addWidget(cornerWidgetContainer); - new QHBoxLayout(cornerWidgetContainer); - } else { - QLayout *layout = cornerWidgetContainer->layout(); - while (layout->count() > 0) { - layout->takeAt(0); - } - } - if (leftWidget) { - leftWidget->setParent(cornerWidgetContainer); - cornerWidgetContainer->layout()->addWidget(leftWidget); - } - if (rightWidget) { - rightWidget->setParent(cornerWidgetContainer); - cornerWidgetContainer->layout()->addWidget(rightWidget); - } -} - - /*! \fn void QMenuBar::setCornerWidget(QWidget *widget, Qt::Corner corner) @@ -1815,9 +1870,7 @@ void QMenuBar::setCornerWidget(QWidget *w, Qt::Corner corner) return; } - if (!d->impl->allowCornerWidgets()) { - d->updateCornerWidgetToolBar(); - } else if (w) { + if (w) { w->setParent(this); w->installEventFilter(this); } @@ -1870,13 +1923,39 @@ QWidget *QMenuBar::cornerWidget(Qt::Corner corner) const void QMenuBar::setNativeMenuBar(bool nativeMenuBar) { Q_D(QMenuBar); - d->impl->setNativeMenuBar(nativeMenuBar); + if (d->nativeMenuBar == -1 || (nativeMenuBar != bool(d->nativeMenuBar))) { + d->nativeMenuBar = nativeMenuBar; +#ifdef Q_WS_MAC + if (!d->nativeMenuBar) { + extern void qt_mac_clear_menubar(); + qt_mac_clear_menubar(); + d->macDestroyMenuBar(); + const QList &menubarActions = actions(); + for (int i = 0; i < menubarActions.size(); ++i) { + const QAction *action = menubarActions.at(i); + if (QMenu *menu = action->menu()) { + delete menu->d_func()->mac_menu; + menu->d_func()->mac_menu = 0; + } + } + } else { + d->macCreateMenuBar(parentWidget()); + } + macUpdateMenuBar(); + updateGeometry(); + if (!d->nativeMenuBar && parentWidget()) + setVisible(true); +#endif + } } bool QMenuBar::isNativeMenuBar() const { Q_D(const QMenuBar); - return d->impl->isNativeMenuBar(); + if (d->nativeMenuBar == -1) { + return !QApplication::instance()->testAttribute(Qt::AA_DontUseNativeMenuBar); + } + return d->nativeMenuBar; } /*! @@ -1913,8 +1992,8 @@ void QMenuBar::setDefaultAction(QAction *act) connect(d->defaultAction, SIGNAL(changed()), this, SLOT(_q_updateDefaultAction())); connect(d->defaultAction, SIGNAL(destroyed()), this, SLOT(_q_updateDefaultAction())); } - if (d->impl->nativeMenuBarAdapter()) { - d->impl->nativeMenuBarAdapter()->rebuild(); + if (d->wce_menubar) { + d->wce_menubar->rebuild(); } #endif } @@ -1973,17 +2052,17 @@ int QMenuBar::insertAny(const QIcon *icon, const QString *text, const QObject *r const QKeySequence *shortcut, const QMenu *popup, int id, int index) { QAction *act = popup ? popup->menuAction() : new QAction(this); - if (id != -1) + if(id != -1) static_cast(act)->setId(id); - if (icon) + if(icon) act->setIcon(*icon); - if (text) + if(text) act->setText(*text); - if (shortcut) + if(shortcut) act->setShortcut(*shortcut); - if (receiver && member) + if(receiver && member) QObject::connect(act, SIGNAL(triggered(bool)), receiver, member); - if (index == -1 || index >= actions().count()) + if(index == -1 || index >= actions().count()) addAction(act); else insertAction(actions().value(index), act); @@ -2005,7 +2084,7 @@ int QMenuBar::insertSeparator(int index) { QAction *act = new QAction(this); act->setSeparator(true); - if (index == -1 || index >= actions().count()) + if(index == -1 || index >= actions().count()) addAction(act); else insertAction(actions().value(index), act); @@ -2017,7 +2096,7 @@ int QMenuBar::insertSeparator(int index) */ bool QMenuBar::setItemParameter(int id, int param) { - if (QAction *act = findActionForId(id)) { + if(QAction *act = findActionForId(id)) { act->d_func()->param = param; return true; } @@ -2029,7 +2108,7 @@ bool QMenuBar::setItemParameter(int id, int param) */ int QMenuBar::itemParameter(int id) const { - if (QAction *act = findActionForId(id)) + if(QAction *act = findActionForId(id)) return act->d_func()->param; return id; } diff --git a/src/gui/widgets/qmenubar_p.h b/src/gui/widgets/qmenubar_p.h index b49e039..5afe713 100644 --- a/src/gui/widgets/qmenubar_p.h +++ b/src/gui/widgets/qmenubar_p.h @@ -61,8 +61,6 @@ #include "qguifunctions_wince.h" #endif -#include "qabstractmenubarimpl_p.h" - #ifndef QT_NO_MENUBAR #ifdef Q_WS_S60 class CCoeControl; @@ -73,7 +71,6 @@ class CEikMenuBar; QT_BEGIN_NAMESPACE #ifndef QT_NO_MENUBAR -class QToolBar; class QMenuBarExtension; class QMenuBarPrivate : public QWidgetPrivate { @@ -81,19 +78,33 @@ class QMenuBarPrivate : public QWidgetPrivate public: QMenuBarPrivate() : itemsDirty(0), currentAction(0), mouseDown(0), closePopupMode(0), defaultPopDown(1), popupState(0), keyboardState(0), altPressed(0), - doChildEffects(false) + nativeMenuBar(-1), doChildEffects(false) #ifdef QT3_SUPPORT , doAutoResize(false) #endif - , impl(0) +#ifdef Q_WS_MAC + , mac_menubar(0) +#endif + #ifdef Q_WS_WINCE - , wceClassicMenu(false) + , wce_menubar(0), wceClassicMenu(false) +#endif +#ifdef Q_WS_S60 + , symbian_menubar(0) #endif { } ~QMenuBarPrivate() { - delete impl; +#ifdef Q_WS_MAC + delete mac_menubar; +#endif +#ifdef Q_WS_WINCE + delete wce_menubar; +#endif +#ifdef Q_WS_S60 + delete symbian_menubar; +#endif } void init(); @@ -125,6 +136,8 @@ public: uint keyboardState : 1, altPressed : 1; QPointer keyboardFocusWidget; + + int nativeMenuBar : 3; // Only has values -1, 0, and 1 //firing of events void activateAction(QAction *, QAction::ActionEvent); @@ -160,14 +173,106 @@ public: #ifdef QT3_SUPPORT bool doAutoResize; #endif - QAbstractMenuBarImpl *impl; +#ifdef Q_WS_MAC + //mac menubar binding + struct QMacMenuBarPrivate { + QList actionItems; + OSMenuRef menu, apple_menu; + QMacMenuBarPrivate(); + ~QMacMenuBarPrivate(); + + void addAction(QAction *, QMacMenuAction* =0); + void addAction(QMacMenuAction *, QMacMenuAction* =0); + void syncAction(QMacMenuAction *); + inline void syncAction(QAction *a) { syncAction(findAction(a)); } + void removeAction(QMacMenuAction *); + inline void removeAction(QAction *a) { removeAction(findAction(a)); } + inline QMacMenuAction *findAction(QAction *a) { + for(int i = 0; i < actionItems.size(); i++) { + QMacMenuAction *act = actionItems[i]; + if(a == act->action) + return act; + } + return 0; + } + } *mac_menubar; + static bool macUpdateMenuBarImmediatly(); + bool macWidgetHasNativeMenubar(QWidget *widget); + void macCreateMenuBar(QWidget *); + void macDestroyMenuBar(); + OSMenuRef macMenu(); +#endif +#ifdef Q_WS_WINCE + void wceCreateMenuBar(QWidget *); + void wceDestroyMenuBar(); + struct QWceMenuBarPrivate { + QList actionItems; + QList actionItemsLeftButton; + QList> actionItemsClassic; + HMENU menuHandle; + HMENU leftButtonMenuHandle; + HWND menubarHandle; + HWND parentWindowHandle; + bool leftButtonIsMenu; + QPointer leftButtonAction; + QMenuBarPrivate *d; + int leftButtonCommand; + + QWceMenuBarPrivate(QMenuBarPrivate *menubar); + ~QWceMenuBarPrivate(); + void addAction(QAction *, QWceMenuAction* =0); + void addAction(QWceMenuAction *, QWceMenuAction* =0); + void syncAction(QWceMenuAction *); + inline void syncAction(QAction *a) { syncAction(findAction(a)); } + void removeAction(QWceMenuAction *); + void rebuild(); + inline void removeAction(QAction *a) { removeAction(findAction(a)); } + inline QWceMenuAction *findAction(QAction *a) { + for(int i = 0; i < actionItems.size(); i++) { + QWceMenuAction *act = actionItems[i]; + if(a == act->action) + return act; + } + return 0; + } + } *wce_menubar; + bool wceClassicMenu; + void wceCommands(uint command); + void wceRefresh(); + bool wceEmitSignals(QList actions, uint command); +#endif +#ifdef Q_WS_S60 + void symbianCreateMenuBar(QWidget *); + void symbianDestroyMenuBar(); + void reparentMenuBar(QWidget *oldParent, QWidget *newParent); + struct QSymbianMenuBarPrivate { + QList actionItems; + QMenuBarPrivate *d; + QSymbianMenuBarPrivate(QMenuBarPrivate *menubar); + ~QSymbianMenuBarPrivate(); + void addAction(QAction *, QSymbianMenuAction* =0); + void addAction(QSymbianMenuAction *, QSymbianMenuAction* =0); + void syncAction(QSymbianMenuAction *); + inline void syncAction(QAction *a) { syncAction(findAction(a)); } + void removeAction(QSymbianMenuAction *); + void rebuild(); + inline void removeAction(QAction *a) { removeAction(findAction(a)); } + inline QSymbianMenuAction *findAction(QAction *a) { + for(int i = 0; i < actionItems.size(); i++) { + QSymbianMenuAction *act = actionItems[i]; + if(a == act->action) + return act; + } + return 0; + } + void insertNativeMenuItems(const QList &actions); + + } *symbian_menubar; + static int symbianCommands(int command); +#endif #ifdef QT_SOFTKEYS_ENABLED QAction *menuBarAction; #endif - - void updateCornerWidgetToolBar(); - QToolBar *cornerWidgetToolBar; - QWidget *cornerWidgetContainer; }; #endif diff --git a/src/gui/widgets/qmenubarimpl.cpp b/src/gui/widgets/qmenubarimpl.cpp deleted file mode 100644 index cbe9198..0000000 --- a/src/gui/widgets/qmenubarimpl.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qmenubarimpl_p.h" - -#ifndef QT_NO_MENUBAR - -#include "qapplication.h" -#include "qdebug.h" -#include "qevent.h" -#include "qmenu.h" -#include "qmenubar.h" - -QT_BEGIN_NAMESPACE - -QMenuBarImpl::~QMenuBarImpl() -{ -#ifdef Q_WS_MAC - macDestroyMenuBar(); -#endif -#ifdef Q_WS_WINCE - if (qt_wince_is_mobile()) - wceDestroyMenuBar(); -#endif -#ifdef Q_WS_S60 - symbianDestroyMenuBar(); -#endif -} - -void QMenuBarImpl::init(QMenuBar *_menuBar) -{ - nativeMenuBar = -1; - menuBar = _menuBar; -#if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) - adapter = 0; -#endif -#ifdef Q_WS_MAC - macCreateMenuBar(menuBar->parentWidget()); - if (adapter) - menuBar->hide(); -#endif -#ifdef Q_WS_WINCE - if (qt_wince_is_mobile()) { - wceCreateMenuBar(menuBar->parentWidget()); - if (adapter) - menuBar->hide(); - } else { - QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true); - } -#endif -} - -bool QMenuBarImpl::allowSetVisible() const -{ -#if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) - // FIXME: Port this to a setVisible() method - /* - if (isNativeMenuBar()) { - if (!visible) - QWidget::setVisible(false); - return; - } - */ - return !isNativeMenuBar(); -#endif - return true; -} - -void QMenuBarImpl::actionEvent(QActionEvent *e) -{ -#if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) - if (adapter) { - if (e->type() == QEvent::ActionAdded) - adapter->addAction(e->action(), e->before()); - else if (e->type() == QEvent::ActionRemoved) - adapter->removeAction(e->action()); - else if (e->type() == QEvent::ActionChanged) - adapter->syncAction(e->action()); - } -#else - Q_UNUSED(e); -#endif -} - -void QMenuBarImpl::handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow) -{ -#ifdef Q_WS_X11 - Q_UNUSED(oldParent) - Q_UNUSED(newParent) - Q_UNUSED(oldWindow) - Q_UNUSED(newWindow) -#endif - -#ifdef Q_WS_MAC - if (isNativeMenuBar() && !macWidgetHasNativeMenubar(newParent)) { - // If the new parent got a native menubar from before, keep that - // menubar rather than replace it with this one (because a parents - // menubar has precedence over children menubars). - macDestroyMenuBar(); - macCreateMenuBar(newParent); - } -#endif -#ifdef Q_WS_WINCE - if (qt_wince_is_mobile() && nativeMenuBarAdapter()) - adapter->rebuild(); -#endif -#ifdef Q_WS_S60 - - // Construct d->impl->nativeMenuBarAdapter() when this code path is entered first time - // and when newParent != NULL - if (!adapter) - symbianCreateMenuBar(newParent); - - // Reparent and rebuild menubar when parent is changed - if (adapter) { - if (oldParent != newParent) - reparentMenuBar(oldParent, newParent); - menuBar->hide(); - adapter->rebuild(); - } - -#ifdef QT_SOFTKEYS_ENABLED - // Constuct menuBarAction when this code path is entered first time - if (!menuBarAction) { - if (newParent) { - menuBarAction = QSoftKeyManager::createAction(QSoftKeyManager::MenuSoftKey, newParent); - newParent->addAction(menuBarAction); - } - } else { - // If reparenting i.e. we already have menuBarAction, remove it from old parent - // and add for a new parent - if (oldParent) - oldParent->removeAction(menuBarAction); - if (newParent) - newParent->addAction(menuBarAction); - } -#endif // QT_SOFTKEYS_ENABLED -#endif // Q_WS_S60 -} - -bool QMenuBarImpl::allowCornerWidgets() const -{ - return true; -} - -void QMenuBarImpl::popupAction(QAction *) -{ -} - -void QMenuBarImpl::setNativeMenuBar(bool value) -{ - if (nativeMenuBar == -1 || (value != bool(nativeMenuBar))) { - nativeMenuBar = value; -#ifdef Q_WS_MAC - if (!nativeMenuBar) { - extern void qt_mac_clear_menubar(); - qt_mac_clear_menubar(); - macDestroyMenuBar(); - const QList &menubarActions = actions(); - for (int i = 0; i < menubarActions.size(); ++i) { - const QAction *action = menubarActions.at(i); - if (QMenu *menu = action->menu()) { - delete menu->d_func()->mac_menu; - menu->d_func()->mac_menu = 0; - } - } - } else { - macCreateMenuBar(parentWidget()); - } - macUpdateMenuBar(); - updateGeometry(); - if (!nativeMenuBar && parentWidget()) - setVisible(true); -#endif - } -} - -bool QMenuBarImpl::isNativeMenuBar() const -{ -#if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) - if (nativeMenuBar == -1) { - return !QApplication::instance()->testAttribute(Qt::AA_DontUseNativeMenuBar); - } - return nativeMenuBar; -#else - return false; -#endif -} - -bool QMenuBarImpl::shortcutsHandledByNativeMenuBar() const -{ -#ifdef Q_WS_MAC - return true; -#else - return false; -#endif -} - -bool QMenuBarImpl::menuBarEventFilter(QObject *, QEvent *) -{ - return false; -} - -QT_END_NAMESPACE - -#endif // QT_NO_MENUBAR diff --git a/src/gui/widgets/qmenubarimpl_p.h b/src/gui/widgets/qmenubarimpl_p.h deleted file mode 100644 index c4ab2df..0000000 --- a/src/gui/widgets/qmenubarimpl_p.h +++ /dev/null @@ -1,183 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QMENUBARIMPL_P_H -#define QMENUBARIMPL_P_H - -#ifndef QT_NO_MENUBAR - -#include "qabstractmenubarimpl_p.h" - -QT_BEGIN_NAMESPACE - -class QMenuBar; - -class QMenuBarImpl : public QAbstractMenuBarImpl -{ -public: - ~QMenuBarImpl(); - - virtual void init(QMenuBar *); - - virtual bool allowSetVisible() const; - - virtual void actionEvent(QActionEvent *e); - - virtual void handleReparent(QWidget *oldParent, QWidget *newParent, QWidget *oldWindow, QWidget *newWindow); - - virtual bool allowCornerWidgets() const; - - virtual void popupAction(QAction*); - - virtual void setNativeMenuBar(bool); - virtual bool isNativeMenuBar() const; - - virtual bool shortcutsHandledByNativeMenuBar() const; - virtual bool menuBarEventFilter(QObject *, QEvent *event); - -private: - QMenuBar *menuBar; - int nativeMenuBar : 3; // Only has values -1, 0, and 1 - -#ifdef Q_WS_MAC - //mac menubar binding - struct QMacMenuBarPrivate { - QList actionItems; - OSMenuRef menu, apple_menu; - QMacMenuBarPrivate(); - ~QMacMenuBarPrivate(); - - void addAction(QAction *, QAction* =0); - void addAction(QMacMenuAction *, QMacMenuAction* =0); - void syncAction(QMacMenuAction *); - inline void syncAction(QAction *a) { syncAction(findAction(a)); } - void removeAction(QMacMenuAction *); - inline void removeAction(QAction *a) { removeAction(findAction(a)); } - inline QMacMenuAction *findAction(QAction *a) { - for (int i = 0; i < actionItems.size(); i++) { - QMacMenuAction *act = actionItems[i]; - if (a == act->action) - return act; - } - return 0; - } - } adapter; - static bool macUpdateMenuBarImmediatly(); - bool macWidgetHasNativeMenubar(QWidget *widget); - void macCreateMenuBar(QWidget *); - void macDestroyMenuBar(); - OSMenuRef macMenu(); -#endif -#ifdef Q_WS_WINCE - void wceCreateMenuBar(QWidget *); - void wceDestroyMenuBar(); - struct QWceMenuBarPrivate { - QList actionItems; - QList actionItemsLeftButton; - QList> actionItemsClassic; - HMENU menuHandle; - HMENU leftButtonMenuHandle; - HWND menubarHandle; - HWND parentWindowHandle; - bool leftButtonIsMenu; - QPointer leftButtonAction; - QMenuBarPrivate *d; - int leftButtonCommand; - - QWceMenuBarPrivate(QMenuBarPrivate *menubar); - ~QWceMenuBarPrivate(); - void addAction(QAction *, QAction* =0); - void addAction(QWceMenuAction *, QWceMenuAction* =0); - void syncAction(QWceMenuAction *); - inline void syncAction(QAction *a) { syncAction(findAction(a)); } - void removeAction(QWceMenuAction *); - void rebuild(); - inline void removeAction(QAction *a) { removeAction(findAction(a)); } - inline QWceMenuAction *findAction(QAction *a) { - for (int i = 0; i < actionItems.size(); i++) { - QWceMenuAction *act = actionItems[i]; - if (a == act->action) - return act; - } - return 0; - } - } adapter; - bool wceClassicMenu; - void wceCommands(uint command); - void wceRefresh(); - bool wceEmitSignals(QList actions, uint command); -#endif -#ifdef Q_WS_S60 - void symbianCreateMenuBar(QWidget *); - void symbianDestroyMenuBar(); - void reparentMenuBar(QWidget *oldParent, QWidget *newParent); - struct QSymbianMenuBarPrivate { - QList actionItems; - QMenuBarPrivate *d; - QSymbianMenuBarPrivate(QMenuBarPrivate *menubar); - ~QSymbianMenuBarPrivate(); - void addAction(QAction *, QAction* =0); - void addAction(QSymbianMenuAction *, QSymbianMenuAction* =0); - void syncAction(QSymbianMenuAction *); - inline void syncAction(QAction *a) { syncAction(findAction(a)); } - void removeAction(QSymbianMenuAction *); - void rebuild(); - inline void removeAction(QAction *a) { removeAction(findAction(a)); } - inline QSymbianMenuAction *findAction(QAction *a) { - for (int i = 0; i < actionItems.size(); i++) { - QSymbianMenuAction *act = actionItems[i]; - if (a == act->action) - return act; - } - return 0; - } - void insertNativeMenuItems(const QList &actions); - - } adapter; - static int symbianCommands(int command); -#endif -}; - -QT_END_NAMESPACE - -#endif // QT_NO_MENUBAR - -#endif /* QMENUBARIMPL_P_H */ diff --git a/src/gui/widgets/widgets.pri b/src/gui/widgets/widgets.pri index e5d6890..669b838 100644 --- a/src/gui/widgets/widgets.pri +++ b/src/gui/widgets/widgets.pri @@ -4,7 +4,6 @@ HEADERS += \ widgets/qbuttongroup.h \ widgets/qabstractbutton.h \ widgets/qabstractbutton_p.h \ - widgets/qabstractmenubarimpl_p.h \ widgets/qabstractslider.h \ widgets/qabstractslider_p.h \ widgets/qabstractspinbox.h \ @@ -85,7 +84,6 @@ HEADERS += \ widgets/qprintpreviewwidget.h SOURCES += \ widgets/qabstractbutton.cpp \ - widgets/qabstractmenubarimpl_p.cpp \ widgets/qabstractslider.cpp \ widgets/qabstractspinbox.cpp \ widgets/qcalendarwidget.cpp \ @@ -112,7 +110,6 @@ SOURCES += \ widgets/qmdisubwindow.cpp \ widgets/qmenu.cpp \ widgets/qmenubar.cpp \ - widgets/qmenubarimpl.cpp \ widgets/qmenudata.cpp \ widgets/qprogressbar.cpp \ widgets/qpushbutton.cpp \ -- cgit v0.12 From 3bff1637cd49617d334c1be63c20e008fac93be1 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Thu, 14 Apr 2011 19:12:59 +0200 Subject: Fix an race condition in the auto test. Deleting the page in the wizard without removing it first leads to a crash when the wizard tries to access a deleted page. Reviewed-by: jasplin --- tests/auto/qwizard/tst_qwizard.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/auto/qwizard/tst_qwizard.cpp b/tests/auto/qwizard/tst_qwizard.cpp index a813727..bbac8a3 100644 --- a/tests/auto/qwizard/tst_qwizard.cpp +++ b/tests/auto/qwizard/tst_qwizard.cpp @@ -1770,8 +1770,11 @@ public: ~TestWizard() { - foreach (int id, pageIds) - delete page(id); + foreach (int id, pageIds) { + QWizardPage *page_to_delete = page(id); + removePage(id); + delete page_to_delete; + } } void applyOperations(const QList &operations) -- cgit v0.12 From 75aea79ce599d5f62a1642a875774544f548c904 Mon Sep 17 00:00:00 2001 From: Martin Smith Date: Fri, 15 Apr 2011 12:22:02 +0200 Subject: qdoc: Completed task QTBUG-18790 --- tools/qdoc3/ditaxmlgenerator.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/qdoc3/ditaxmlgenerator.cpp b/tools/qdoc3/ditaxmlgenerator.cpp index e394249..5f44cd8 100644 --- a/tools/qdoc3/ditaxmlgenerator.cpp +++ b/tools/qdoc3/ditaxmlgenerator.cpp @@ -769,6 +769,7 @@ int DitaXmlGenerator::generateAtom(const Atom *atom, case Atom::Code: { writeStartTag(DT_codeblock); + xmlWriter().writeAttribute("outputclass","cpp"); QString chars = trimmedTrailing(atom->string()); writeText(chars, marker, relative); writeEndTag(); // @@ -776,6 +777,7 @@ int DitaXmlGenerator::generateAtom(const Atom *atom, break; case Atom::Qml: writeStartTag(DT_codeblock); + xmlWriter().writeAttribute("outputclass","qml"); writeText(trimmedTrailing(atom->string()), marker, relative); writeEndTag(); // break; -- cgit v0.12 From 1348f4f0853155182d2ea5836902794d1e43980c Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 22 Mar 2011 10:57:59 +0100 Subject: Long live QRawFont! The QGlyphs API was initially attempted with a bastardization of QFont which was meant to encapsulate a single, physical font instance (a QFontEngine) where a set of glyph indexes would make sense. This is not how QFont was intended to be used, and it caused several issues. At the same time, the requirement for loading a font from ttf/otf data and be able to access it and use it without polluting the rest of the process with the font arose. To support these two APIs we introduce QRawFont, which is an abstraction on top of a single physical font. Done-with: Jiang Jiang --- src/corelib/global/qglobal.h | 6 + src/gui/painting/qpaintbuffer.cpp | 23 +- src/gui/painting/qpainter.cpp | 54 +- src/gui/painting/qpainter.h | 2 + src/gui/painting/qpainter_p.h | 10 +- src/gui/text/qfont.cpp | 26 +- src/gui/text/qfont_win.cpp | 17 +- src/gui/text/qfontdatabase.cpp | 27 +- src/gui/text/qfontdatabase_mac.cpp | 7 +- src/gui/text/qfontdatabase_s60.cpp | 2 +- src/gui/text/qfontdatabase_win.cpp | 90 +-- src/gui/text/qfontengine.cpp | 18 - src/gui/text/qfontengine_coretext.mm | 316 +++++++---- src/gui/text/qfontengine_coretext_p.h | 27 +- src/gui/text/qfontengine_ft.cpp | 162 +++++- src/gui/text/qfontengine_ft_p.h | 15 +- src/gui/text/qfontengine_mac.mm | 21 - src/gui/text/qfontengine_mac_p.h | 2 - src/gui/text/qfontengine_p.h | 5 +- src/gui/text/qfontengine_x11_p.h | 1 + src/gui/text/qfontenginedirectwrite.cpp | 54 +- src/gui/text/qfontenginedirectwrite_p.h | 11 +- src/gui/text/qglyphs.cpp | 97 +++- src/gui/text/qglyphs.h | 19 +- src/gui/text/qglyphs_p.h | 25 +- src/gui/text/qrawfont.cpp | 612 ++++++++++++++++++++ src/gui/text/qrawfont.h | 140 +++++ src/gui/text/qrawfont_ft.cpp | 189 +++++++ src/gui/text/qrawfont_mac.cpp | 105 ++++ src/gui/text/qrawfont_p.h | 132 +++++ src/gui/text/qrawfont_win.cpp | 750 +++++++++++++++++++++++++ src/gui/text/qtextlayout.cpp | 58 +- src/gui/text/qtextlayout.h | 5 + src/gui/text/qtextobject.cpp | 2 + src/gui/text/qtextobject.h | 2 + src/gui/text/text.pri | 22 +- tests/auto/gui.pro | 1 + tests/auto/qglyphs/tst_qglyphs.cpp | 17 +- tests/auto/qrawfont/qrawfont.pro | 13 + tests/auto/qrawfont/testfont.ttf | Bin 0 -> 63212 bytes tests/auto/qrawfont/testfont_bold_italic.ttf | Bin 0 -> 49760 bytes tests/auto/qrawfont/tst_qrawfont.cpp | 812 +++++++++++++++++++++++++++ 42 files changed, 3509 insertions(+), 388 deletions(-) create mode 100644 src/gui/text/qrawfont.cpp create mode 100644 src/gui/text/qrawfont.h create mode 100644 src/gui/text/qrawfont_ft.cpp create mode 100644 src/gui/text/qrawfont_mac.cpp create mode 100644 src/gui/text/qrawfont_p.h create mode 100644 src/gui/text/qrawfont_win.cpp create mode 100644 tests/auto/qrawfont/qrawfont.pro create mode 100644 tests/auto/qrawfont/testfont.ttf create mode 100644 tests/auto/qrawfont/testfont_bold_italic.ttf create mode 100644 tests/auto/qrawfont/tst_qrawfont.cpp diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 7c5c354..d8ffd6d 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -2743,6 +2743,12 @@ QT_LICENSED_MODULE(DBus) # endif #endif +#if !(defined(Q_WS_WIN) && !defined(Q_WS_WINCE)) \ + && !(defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)) \ + && !(defined(Q_WS_X11) && !defined(QT_NO_FREETYPE)) +# define QT_NO_RAWFONT +#endif + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index dd4b3db..7870def 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -1754,26 +1755,38 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) painter->setClipRegion(region, Qt::ClipOperation(cmd.extra)); break; } +#if !defined(QT_NO_RAWFONT) case QPaintBufferPrivate::Cmd_DrawStaticText: { QVariantList variants(d->variants.at(cmd.offset).value()); QFont font = variants.at(0).value(); - QVector glyphs; + QVector glyphIndexes; QVector positions; for (int i=0; i<(variants.size() - 1) / 2; ++i) { - glyphs.append(variants.at(i*2 + 1).toUInt()); + glyphIndexes.append(variants.at(i*2 + 1).toUInt()); positions.append(variants.at(i*2 + 2).toPointF()); } painter->setFont(font); - qt_draw_glyphs(painter, glyphs.constData(), positions.constData(), glyphs.size()); - - break; + QRawFont rawFont; + QRawFontPrivate *rawFontD = QRawFontPrivate::get(rawFont); + QFontPrivate *fontD = QFontPrivate::get(font); + rawFontD->fontEngine = fontD->engineForScript(QUnicodeTables::Common); + rawFontD->fontEngine->ref.ref(); + + QGlyphs glyphs; + glyphs.setFont(rawFont); + glyphs.setGlyphIndexes(glyphIndexes); + glyphs.setPositions(positions); + + painter->drawGlyphs(QPointF(), glyphs); + break; } +#endif case QPaintBufferPrivate::Cmd_DrawText: { QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index eddb9eb..cbd16ae 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -75,6 +75,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -5798,12 +5799,14 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR \sa QGlyphs::setFont(), QGlyphs::setPositions(), QGlyphs::setGlyphIndexes() */ +#if !defined(QT_NO_RAWFONT) void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs) { Q_D(QPainter); - QFont oldFont = d->state->font; - d->state->font = glyphs.font(); + QRawFont font = glyphs.font(); + if (!font.isValid()) + return; QVector glyphIndexes = glyphs.glyphIndexes(); QVector glyphPositions = glyphs.positions(); @@ -5822,39 +5825,20 @@ void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs) fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition); } - d->drawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count); - - d->state->font = oldFont; + d->drawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count, font, glyphs.overline(), + glyphs.underline(), glyphs.strikeOut()); } -void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, const QPointF *positionArray, - int glyphCount) -{ - QVarLengthArray positions(glyphCount); - for (int i=0; idrawGlyphs(const_cast(glyphArray), positions.data(), glyphCount); -} - -void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, int glyphCount) +void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, int glyphCount, + const QRawFont &font, bool overline, bool underline, + bool strikeOut) { Q_Q(QPainter); updateState(state); - QFontEngine *fontEngine = state->font.d->engineForScript(QUnicodeTables::Common); - - while (fontEngine->type() == QFontEngine::Multi) { - // Pick engine based on first glyph in array if we are using a multi engine. - // (all glyphs must be for same font) - int engineIdx = 0; - if (glyphCount > 0) - engineIdx = glyphArray[0] >> 24; - - fontEngine = static_cast(fontEngine)->engine(engineIdx); - } + QRawFontPrivate *fontD = QRawFontPrivate::get(font); + QFontEngine *fontEngine = fontD->fontEngine; QFixed leftMost; QFixed rightMost; @@ -5889,7 +5873,6 @@ void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, in extended->drawStaticTextItem(&staticTextItem); } else { QTextItemInt textItem; - textItem.f = &state->font; textItem.fontEngine = fontEngine; QVarLengthArray advances(glyphCount); @@ -5911,20 +5894,21 @@ void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, in } QTextItemInt::RenderFlags flags; - if (state->font.underline()) + if (underline) flags |= QTextItemInt::Underline; - if (state->font.overline()) + if (overline) flags |= QTextItemInt::Overline; - if (state->font.strikeOut()) + if (strikeOut) flags |= QTextItemInt::StrikeOut; drawTextItemDecoration(q, QPointF(leftMost.toReal(), baseLine.toReal()), fontEngine, - (state->font.underline() - ? QTextCharFormat::SingleUnderline - : QTextCharFormat::NoUnderline), + (underline + ? QTextCharFormat::SingleUnderline + : QTextCharFormat::NoUnderline), flags, width.toReal(), QTextCharFormat()); } +#endif // QT_NO_RAWFONT /*! diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index 604225e..1a432e6 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -399,7 +399,9 @@ public: void setLayoutDirection(Qt::LayoutDirection direction); Qt::LayoutDirection layoutDirection() const; +#if !defined(QT_NO_RAWFONT) void drawGlyphs(const QPointF &position, const QGlyphs &glyphs); +#endif void drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText); inline void drawStaticText(const QPoint &topLeftPosition, const QStaticText &staticText); diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 26d8fc3..205c10a 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -184,6 +184,7 @@ struct QPainterDummyState QTransform transform; }; +class QRawFont; class QPainterPrivate { Q_DECLARE_PUBLIC(QPainter) @@ -229,7 +230,12 @@ public: void draw_helper(const QPainterPath &path, DrawOperation operation = StrokeAndFillDraw); void drawStretchedGradient(const QPainterPath &path, DrawOperation operation); void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation); - void drawGlyphs(quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount); + +#if !defined(QT_NO_RAWFONT) + void drawGlyphs(quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount, + const QRawFont &font, bool overline = false, bool underline = false, + bool strikeOut = false); +#endif void updateMatrix(); void updateInvMatrix(); @@ -259,8 +265,6 @@ public: }; Q_GUI_EXPORT void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation); -Q_GUI_EXPORT void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, - const QPointF *positionArray, int glyphCount); QString qt_generate_brush_key(const QBrush &brush); diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index f77e237..b8cfb1f 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -282,27 +282,16 @@ QFontPrivate::~QFontPrivate() scFont = 0; } -#if !defined(Q_WS_MAC) extern QMutex *qt_fontdatabase_mutex(); -QFontEngine *QFontPrivate::engineForScript(int script) const -{ - QMutexLocker locker(qt_fontdatabase_mutex()); - if (script >= QUnicodeTables::Inherited) - script = QUnicodeTables::Common; - if (engineData && engineData->fontCache != QFontCache::instance()) { - // throw out engineData that came from a different thread - engineData->ref.deref(); - engineData = 0; - } - if (!engineData || !engineData->engines[script]) - QFontDatabase::load(this, script); - return engineData->engines[script]; -} +#if !defined(Q_WS_MAC) +#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engines[script] #else +#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engine +#endif + QFontEngine *QFontPrivate::engineForScript(int script) const { - extern QMutex *qt_fontdatabase_mutex(); QMutexLocker locker(qt_fontdatabase_mutex()); if (script >= QUnicodeTables::Inherited) script = QUnicodeTables::Common; @@ -311,11 +300,10 @@ QFontEngine *QFontPrivate::engineForScript(int script) const engineData->ref.deref(); engineData = 0; } - if (!engineData || !engineData->engine) + if (!engineData || !QT_FONT_ENGINE_FROM_DATA(engineData, script)) QFontDatabase::load(this, script); - return engineData->engine; + return QT_FONT_ENGINE_FROM_DATA(engineData, script); } -#endif void QFontPrivate::alterCharForCapitalization(QChar &c) const { switch (capital) { diff --git a/src/gui/text/qfont_win.cpp b/src/gui/text/qfont_win.cpp index 7d710ea..3ef761b 100644 --- a/src/gui/text/qfont_win.cpp +++ b/src/gui/text/qfont_win.cpp @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE extern HDC shared_dc(); // common dc for all fonts +extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp // ### maybe move to qapplication_win QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/) @@ -65,20 +66,8 @@ QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/) QString family = QString::fromWCharArray(lf.lfFaceName); QFont qf(family); qf.setItalic(lf.lfItalic); - if (lf.lfWeight != FW_DONTCARE) { - int weight; - if (lf.lfWeight < 400) - weight = QFont::Light; - else if (lf.lfWeight < 600) - weight = QFont::Normal; - else if (lf.lfWeight < 700) - weight = QFont::DemiBold; - else if (lf.lfWeight < 800) - weight = QFont::Bold; - else - weight = QFont::Black; - qf.setWeight(weight); - } + if (lf.lfWeight != FW_DONTCARE) + qf.setWeight(weightFromInteger(lf.lfWeight)); int lfh = qAbs(lf.lfHeight); qf.setPointSizeF(lfh * 72.0 / GetDeviceCaps(shared_dc(),LOGPIXELSY)); qf.setUnderline(false); diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 94f21b8..36b0ea9 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -136,6 +136,21 @@ static int getFontWeight(const QString &weightString) return (int) QFont::Normal; } +// convert 0 ~ 1000 integer to QFont::Weight +QFont::Weight weightFromInteger(int weight) +{ + if (weight < 400) + return QFont::Light; + else if (weight < 600) + return QFont::Normal; + else if (weight < 700) + return QFont::DemiBold; + else if (weight < 800) + return QFont::Bold; + else + return QFont::Black; +} + struct QtFontEncoding { signed int encoding : 16; @@ -497,8 +512,6 @@ QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create) // ### copied to tools/makeqpf/qpf2.cpp -#if (defined(Q_WS_QWS) && !defined(QT_NO_FREETYPE)) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) || (defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)) - // see the Unicode subset bitfields in the MSDN docs static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { // Any, @@ -576,7 +589,7 @@ static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { #define JapaneseCsbBit 17 #define KoreanCsbBit 21 -static QList determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]) +QList qt_determine_writing_systems_from_truetype_bits(quint32 unicodeRange[4], quint32 codePageRange[2]) { QList writingSystems; bool hasScript = false; @@ -623,7 +636,6 @@ static QList determineWritingSystemsFromTrueTypeBi return writingSystems; } -#endif #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // class with virtual destructor, derived in qfontdatabase_s60.cpp @@ -873,7 +885,7 @@ QStringList QFontDatabasePrivate::addTTFile(const QByteArray &file, const QByteA os2->ulCodePageRange1, os2->ulCodePageRange2 }; - writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + writingSystems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange); //for (int i = 0; i < writingSystems.count(); ++i) // qDebug() << QFontDatabase::writingSystemName(writingSystems.at(i)); } @@ -936,6 +948,11 @@ static const int scriptForWritingSystem[] = { QUnicodeTables::Nko // Nko }; +int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem) +{ + return scriptForWritingSystem[writingSystem]; +} + #if defined Q_WS_QWS || (defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)) || defined(Q_WS_WIN) static inline bool requiresOpenType(int writingSystem) diff --git a/src/gui/text/qfontdatabase_mac.cpp b/src/gui/text/qfontdatabase_mac.cpp index ad2c1b2..5ba236b 100644 --- a/src/gui/text/qfontdatabase_mac.cpp +++ b/src/gui/text/qfontdatabase_mac.cpp @@ -72,7 +72,7 @@ static void initWritingSystems(QtFontFamily *family, ATSFontRef atsFont) qFromBigEndian(os2Table.data() + 54) }; quint32 codePageRange[2] = { qFromBigEndian(os2Table.data() + 78), qFromBigEndian(os2Table.data() + 82) }; - QList systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + QList systems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange); #if 0 QCFString name; ATSFontGetName(atsFont, kATSOptionFlagsDefault, &name); @@ -244,6 +244,11 @@ static const char *styleHint(const QFontDef &request) return stylehint; } +static inline float weightToFloat(unsigned int weight) +{ + return (weight - 50) / 100.0; +} + void QFontDatabase::load(const QFontPrivate *d, int script) { // sanity checks diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp index 6d3970e..1db4a7d 100644 --- a/src/gui/text/qfontdatabase_s60.cpp +++ b/src/gui/text/qfontdatabase_s60.cpp @@ -521,7 +521,7 @@ static bool registerScreenDeviceFont(int screenDeviceFontIndex, qFromBigEndian(ulCodePageRange + 4) }; const QList writingSystems = - determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange); foreach (const QFontDatabase::WritingSystem system, writingSystems) family->writingSystems[system] = QtFontFamily::Supported; return true; diff --git a/src/gui/text/qfontdatabase_win.cpp b/src/gui/text/qfontdatabase_win.cpp index 8279195..05b7509 100644 --- a/src/gui/text/qfontdatabase_win.cpp +++ b/src/gui/text/qfontdatabase_win.cpp @@ -242,6 +242,8 @@ error: return i18n_name; } +extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp + static void addFontToDatabase(QString familyName, const QString &scriptName, TEXTMETRIC *textmetric, @@ -274,16 +276,7 @@ void addFontToDatabase(QString familyName, const QString &scriptName, if (familyName[0] != QLatin1Char('@') && !familyName.startsWith(QLatin1String("WST_"))) { QtFontStyle::Key styleKey; styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal; - if (weight < 400) - styleKey.weight = QFont::Light; - else if (weight < 600) - styleKey.weight = QFont::Normal; - else if (weight < 700) - styleKey.weight = QFont::DemiBold; - else if (weight < 800) - styleKey.weight = QFont::Bold; - else - styleKey.weight = QFont::Black; + styleKey.weight = weightFromInteger(weight); QtFontFamily *family = privateDb()->family(familyName, true); @@ -340,7 +333,7 @@ void addFontToDatabase(QString familyName, const QString &scriptName, quint32 codePageRange[2] = { signature->fsCsb[0], signature->fsCsb[1] }; - QList systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + QList systems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange); for (int i = 0; i < systems.count(); ++i) { QFontDatabase::WritingSystem writingSystem = systems.at(i); @@ -530,26 +523,26 @@ static inline void load(const QString &family = QString(), int = -1) -static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, const QFontPrivate *fp) +static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, HDC fontHdc, int dpi) { fe->fontDef = request; // most settings are equal - HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fp->hdc) ? fp->hdc : shared_dc(); + HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fontHdc) ? fontHdc : shared_dc(); SelectObject(dc, fe->hfont); wchar_t n[64]; GetTextFace(dc, 64, n); fe->fontDef.family = QString::fromWCharArray(n); fe->fontDef.fixedPitch = !(fe->tm.tmPitchAndFamily & TMPF_FIXED_PITCH); if (fe->fontDef.pointSize < 0) { - fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / fp->dpi; + fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / dpi; } else if (fe->fontDef.pixelSize == -1) { - fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * fp->dpi / 72.); + fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.); } } #if !defined(QT_NO_DIRECTWRITE) static void initFontInfo(QFontEngineDirectWrite *fe, const QFontDef &request, - const QFontPrivate *fp, IDWriteFont *font) + int dpi, IDWriteFont *font) { fe->fontDef = request; @@ -601,9 +594,9 @@ static void initFontInfo(QFontEngineDirectWrite *fe, const QFontDef &request, qErrnoWarning(hr, "initFontInfo: Failed to get family name"); if (fe->fontDef.pointSize < 0) - fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / fp->dpi; + fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / dpi; else if (fe->fontDef.pixelSize == -1) - fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * fp->dpi / 72.); + fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.); } #endif @@ -679,20 +672,21 @@ static inline HFONT systemFont() #define DEFAULT_GUI_FONT 17 #endif -static -QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &request, const QtFontDesc *desc, - const QStringList &family_list) +static QFontEngine *loadEngine(int script, const QFontDef &request, + HDC fontHdc, int dpi, bool rawMode, + const QtFontDesc *desc, + const QStringList &family_list) { LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); - bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fp->hdc; + bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fontHdc; HDC hdc = shared_dc(); - QString font_name = desc->family->name; + QString font_name = desc != 0 ? desc->family->name : request.family; if (useDevice) { - hdc = fp->hdc; + hdc = fontHdc; font_name = request.family; } @@ -710,9 +704,9 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ bool useDirectWrite = false; #endif - if (fp->rawMode) { // will choose a stock font + if (rawMode) { // will choose a stock font int f, deffnt = SYSTEM_FONT; - QString fam = desc->family->name.toLower(); + QString fam = desc != 0 ? desc->family->name.toLower() : request.family.toLower(); if (fam == QLatin1String("default")) f = deffnt; else if (fam == QLatin1String("system")) @@ -766,11 +760,11 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; - if (desc->style->key.weight == 50) + if (desc == 0 || desc->style->key.weight == 50) lf.lfWeight = FW_DONTCARE; else lf.lfWeight = (desc->style->key.weight*900)/99; - lf.lfItalic = (desc->style->key.style != QFont::StyleNormal); + lf.lfItalic = (desc != 0 && desc->style->key.style != QFont::StyleNormal); lf.lfCharSet = DEFAULT_CHARSET; int strat = OUT_DEFAULT_PRECIS; @@ -901,9 +895,11 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ &lf, &directWriteFont); if (FAILED(hr)) { +#ifndef QT_NO_DEBUG qErrnoWarning("QFontEngine::loadEngine: CreateFontFromLOGFONT failed " "for %ls (0x%lx)", lf.lfFaceName, hr); +#endif } else { DeleteObject(hfont); useDirectWrite = true; @@ -933,22 +929,27 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ } } - initFontInfo(few, request, fp); + initFontInfo(few, request, fontHdc, dpi); fe = few; } #if !defined(QT_NO_DIRECTWRITE) else { QFontDatabasePrivate *db = privateDb(); - QFontEngineDirectWrite *fedw = new QFontEngineDirectWrite(font_name, - db->directWriteFactory, - db->directWriteGdiInterop, - directWriteFont, - request.pixelSize); - initFontInfo(fedw, request, fp, directWriteFont); + IDWriteFontFace *directWriteFontFace = NULL; + HRESULT hr = directWriteFont->CreateFontFace(&directWriteFontFace); + if (SUCCEEDED(hr)) { + QFontEngineDirectWrite *fedw = new QFontEngineDirectWrite(db->directWriteFactory, + directWriteFontFace, + request.pixelSize); + + initFontInfo(fedw, request, dpi, directWriteFont); - fe = fedw; + fe = fedw; + } else { + qErrnoWarning(hr, "QFontEngine::loadEngine: CreateFontFace failed"); + } } if (directWriteFont != 0) @@ -957,6 +958,7 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ if(script == QUnicodeTables::Common && !(request.styleStrategy & QFont::NoFontMerging) + && desc != 0 && !(desc->family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) { if(!tryFonts) { LANGID lid = GetUserDefaultLangID(); @@ -993,6 +995,20 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ return fe; } +QFontEngine *qt_load_font_engine_win(const QFontDef &request) +{ + // From qfont.cpp + extern int qt_defaultDpi(); + + QFontCache::Key key(request, QUnicodeTables::Common); + QFontEngine *fe = QFontCache::instance()->findEngine(key); + if (fe != 0) + return fe; + else + return loadEngine(QUnicodeTables::Common, request, 0, qt_defaultDpi(), false, 0, + QStringList()); +} + const char *styleHint(const QFontDef &request) { const char *stylehint = 0; @@ -1053,7 +1069,7 @@ static QFontEngine *loadWin(const QFontPrivate *d, int script, const QFontDef &r } if (!desc.family) break; - fe = loadEngine(script, d, req, &desc, family_list); + fe = loadEngine(script, req, d->hdc, d->dpi, d->rawMode, &desc, family_list); if (!fe) blacklistedFamilies.append(desc.familyIndex); } diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 3adf4eb..2f76cc6 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -237,24 +237,6 @@ glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix return metrics; } -QFont QFontEngine::createExplicitFont() const -{ - return createExplicitFontWithName(fontDef.family); -} - -QFont QFontEngine::createExplicitFontWithName(const QString &familyName) const -{ - QFont font(familyName); - font.setStyleStrategy(QFont::NoFontMerging); - font.setWeight(fontDef.weight); - font.setItalic(fontDef.style == QFont::StyleItalic); - if (fontDef.pointSize < 0) - font.setPixelSize(fontDef.pixelSize); - else - font.setPointSizeF(fontDef.pointSize); - return font; -} - QFixed QFontEngine::xHeight() const { QGlyphLayoutArray<8> glyphs; diff --git a/src/gui/text/qfontengine_coretext.mm b/src/gui/text/qfontengine_coretext.mm index 4d9192e..20b3730 100644 --- a/src/gui/text/qfontengine_coretext.mm +++ b/src/gui/text/qfontengine_coretext.mm @@ -52,6 +52,31 @@ QT_BEGIN_NAMESPACE static float SYNTHETIC_ITALIC_SKEW = tanf(14 * acosf(0) / 90); +static void loadAdvancesForGlyphs(CTFontRef ctfont, + QVarLengthArray &cgGlyphs, + QGlyphLayout *glyphs, int len, + QTextEngine::ShaperFlags flags, + const QFontDef &fontDef) +{ + Q_UNUSED(flags); + QVarLengthArray advances(len); + CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len); + + for (int i = 0; i < len; ++i) { + if (glyphs->glyphs[i] & 0xff000000) + continue; + glyphs->advances_x[i] = QFixed::fromReal(advances[i].width); + glyphs->advances_y[i] = QFixed::fromReal(advances[i].height); + } + + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { + for (int i = 0; i < len; ++i) { + glyphs->advances_x[i] = glyphs->advances_x[i].round(); + glyphs->advances_y[i] = glyphs->advances_y[i].round(); + } + } +} + QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const QFontDef &fontDef, bool kerning) : QFontEngineMulti(0) { @@ -83,7 +108,31 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const ctfont = baseFont; CFRetain(ctfont); } + init(kerning); +} + +QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(CGFontRef cgFontRef, const QFontDef &fontDef, bool kerning) + : QFontEngineMulti(0) +{ + this->fontDef = fontDef; + + transform = CGAffineTransformIdentity; + if (fontDef.stretch != 100) { + transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); + } + + ctfont = CTFontCreateWithGraphicsFont(cgFontRef, fontDef.pixelSize, &transform, NULL); + init(kerning); +} + +QCoreTextFontEngineMulti::~QCoreTextFontEngineMulti() +{ + CFRelease(ctfont); +} +void QCoreTextFontEngineMulti::init(bool kerning) +{ + Q_ASSERT(ctfont != NULL); attributeDict = CFDictionaryCreateMutable(0, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); @@ -94,26 +143,20 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const CFDictionaryAddValue(attributeDict, kCTKernAttributeName, noKern); } - QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef, this); + QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef); fe->ref.ref(); engines.append(fe); - -} - -QCoreTextFontEngineMulti::~QCoreTextFontEngineMulti() -{ - CFRelease(ctfont); } -uint QCoreTextFontEngineMulti::fontIndexForFont(CTFontRef id) const +uint QCoreTextFontEngineMulti::fontIndexForFont(CTFontRef font) const { for (int i = 0; i < engines.count(); ++i) { - if (CFEqual(engineAt(i)->ctfont, id)) + if (CFEqual(engineAt(i)->ctfont, font)) return i; } QCoreTextFontEngineMulti *that = const_cast(this); - QCoreTextFontEngine *fe = new QCoreTextFontEngine(id, fontDef, that); + QCoreTextFontEngine *fe = new QCoreTextFontEngine(font, fontDef); fe->ref.ref(); that->engines.append(fe); return engines.count() - 1; @@ -317,72 +360,45 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay if (flags & QTextEngine::GlyphIndicesOnly) return true; - QVarLengthArray advances(len); - CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len); - - for (int i = 0; i < len; ++i) { - if (glyphs->glyphs[i] & 0xff000000) - continue; - glyphs->advances_x[i] = QFixed::fromReal(advances[i].width); - glyphs->advances_y[i] = QFixed::fromReal(advances[i].height); - } - - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { - for (int i = 0; i < len; ++i) { - glyphs->advances_x[i] = glyphs->advances_x[i].round(); - glyphs->advances_y[i] = glyphs->advances_y[i].round(); - } - } - + loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, len, flags, fontDef); return true; } -void QCoreTextFontEngineMulti::recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const -{ -} -void QCoreTextFontEngineMulti::doKerning(int , QGlyphLayout *, QTextEngine::ShaperFlags) const -{ -} - void QCoreTextFontEngineMulti::loadEngine(int) { // Do nothing Q_ASSERT(false); } +extern int qt_antialiasing_threshold; // from qapplication.cpp +static inline CGAffineTransform transformFromFontDef(const QFontDef &fontDef) +{ + CGAffineTransform transform = CGAffineTransformIdentity; + if (fontDef.stretch != 100) + transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); + return transform; +} -QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def, - QCoreTextFontEngineMulti *multiEngine) +QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def) { fontDef = def; - parentEngine = multiEngine; - synthesisFlags = 0; + transform = transformFromFontDef(fontDef); ctfont = font; CFRetain(ctfont); - cgFont = CTFontCopyGraphicsFont(ctfont, NULL); - CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont); - if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait)) { - synthesisFlags |= SynthesizedBold; - } - - if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait)) { - synthesisFlags |= SynthesizedItalic; - } - transform = CGAffineTransformIdentity; - if (fontDef.stretch != 100) { - transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); - } - QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2')); - if (os2Table.size() >= 10) - fsType = qFromBigEndian(reinterpret_cast(os2Table.constData() + 8)); + cgFont = CTFontCopyGraphicsFont(font, NULL); + init(); +} - QSettings appleSettings(QLatin1String("apple.com")); - QVariant appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold")); - if (appleValue.isValid()) - antialiasing_threshold = appleValue.toInt(); - else - antialiasing_threshold = -1; +QCoreTextFontEngine::QCoreTextFontEngine(CGFontRef font, const QFontDef &def) +{ + fontDef = def; + transform = transformFromFontDef(fontDef); + cgFont = font; + // Keep reference count balanced + CFRetain(cgFont); + ctfont = CTFontCreateWithGraphicsFont(font, fontDef.pixelSize, &transform, NULL); + init(); } QCoreTextFontEngine::~QCoreTextFontEngine() @@ -391,9 +407,89 @@ QCoreTextFontEngine::~QCoreTextFontEngine() CFRelease(ctfont); } -bool QCoreTextFontEngine::stringToCMap(const QChar *, int, QGlyphLayout *, int *, QTextEngine::ShaperFlags) const +extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp + +int getTraitValue(CFDictionaryRef allTraits, CFStringRef trait) { - return false; + if (CFDictionaryContainsKey(allTraits, trait)) { + CFNumberRef traitNum = (CFNumberRef) CFDictionaryGetValue(allTraits, trait); + float v = 0; + CFNumberGetValue(traitNum, kCFNumberFloatType, &v); + // the value we get from CFNumberRef is from -1.0 to 1.0 + int value = v * 500 + 500; + return value; + } + + return 0; +} + +void QCoreTextFontEngine::init() +{ + Q_ASSERT(ctfont != NULL); + Q_ASSERT(cgFont != NULL); + + QCFString family = CTFontCopyFamilyName(ctfont); + fontDef.family = family; + + synthesisFlags = 0; + CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont); + if (traits & kCTFontItalicTrait) + fontDef.style = QFont::StyleItalic; + + CFDictionaryRef allTraits = CTFontCopyTraits(ctfont); + fontDef.weight = weightFromInteger(getTraitValue(allTraits, kCTFontWeightTrait)); + int slant = getTraitValue(allTraits, kCTFontSlantTrait); + if (slant > 500 && !(traits & kCTFontItalicTrait)) + fontDef.style = QFont::StyleOblique; + CFRelease(allTraits); + + if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait)) + synthesisFlags |= SynthesizedBold; + // XXX: we probably don't need to synthesis italic for oblique font + if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait)) + synthesisFlags |= SynthesizedItalic; + + avgCharWidth = 0; + QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2')); + unsigned emSize = CTFontGetUnitsPerEm(ctfont); + if (os2Table.size() >= 10) { + fsType = qFromBigEndian(reinterpret_cast(os2Table.constData() + 8)); + // qAbs is a workaround for weird fonts like Lucida Grande + qint16 width = qAbs(qFromBigEndian(reinterpret_cast(os2Table.constData() + 2))); + avgCharWidth = QFixed::fromReal(width * fontDef.pixelSize / emSize); + } else + avgCharWidth = QFontEngine::averageCharWidth(); + + ctMaxCharWidth = ctMinLeftBearing = ctMinRightBearing = 0; + QByteArray hheaTable = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a')); + if (hheaTable.size() >= 16) { + quint16 width = qFromBigEndian(reinterpret_cast(hheaTable.constData() + 10)); + ctMaxCharWidth = width * fontDef.pixelSize / emSize; + qint16 bearing = qFromBigEndian(reinterpret_cast(hheaTable.constData() + 12)); + ctMinLeftBearing = bearing * fontDef.pixelSize / emSize; + bearing = qFromBigEndian(reinterpret_cast(hheaTable.constData() + 14)); + ctMinRightBearing = bearing * fontDef.pixelSize / emSize; + } +} + +bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, + int *nglyphs, QTextEngine::ShaperFlags flags) const +{ + *nglyphs = len; + QCFType cfstring; + + QVarLengthArray cgGlyphs(len); + CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len); + + for (int i = 0; i < len; ++i) + if (cgGlyphs[i]) + glyphs->glyphs[i] = cgGlyphs[i]; + + if (flags & QTextEngine::GlyphIndicesOnly) + return true; + + loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, len, flags, fontDef); + return true; } glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs) @@ -407,6 +503,7 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs) } return glyph_metrics_t(0, -(ascent()), w - lastRightBearing(glyphs, round), ascent()+descent(), w, 0); } + glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph) { glyph_metrics_t ret; @@ -460,31 +557,29 @@ QFixed QCoreTextFontEngine::xHeight() const ? QFixed::fromReal(CTFontGetXHeight(ctfont)).round() : QFixed::fromReal(CTFontGetXHeight(ctfont)); } + QFixed QCoreTextFontEngine::averageCharWidth() const { - // ### Need to implement properly and get the information from the OS/2 Table. return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - ? QFontEngine::averageCharWidth().round() - : QFontEngine::averageCharWidth(); + ? avgCharWidth.round() : avgCharWidth; } qreal QCoreTextFontEngine::maxCharWidth() const { - // ### Max Help! - return 0; - + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? qRound(ctMaxCharWidth) : ctMaxCharWidth; } + qreal QCoreTextFontEngine::minLeftBearing() const { - // ### Min Help! - return 0; - + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? qRound(ctMinLeftBearing) : ctMinLeftBearing; } + qreal QCoreTextFontEngine::minRightBearing() const { - // ### Max Help! (even thought it's right) - return 0; - + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? qRound(ctMinRightBearing) : ctMinLeftBearing; } void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight) @@ -602,12 +697,6 @@ void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *position } } -QFont QCoreTextFontEngine::createExplicitFont() const -{ - QString familyName = QCFString::toQString(CTFontCopyFamilyName(ctfont)); - return createExplicitFontWithName(familyName); -} - QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int /*margin*/, bool aa) { const glyph_metrics_t br = boundingBox(glyph); @@ -624,7 +713,7 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition cgflags); CGContextSetFontSize(ctx, fontDef.pixelSize); CGContextSetShouldAntialias(ctx, aa || - (fontDef.pointSize > antialiasing_threshold + (fontDef.pointSize > qt_antialiasing_threshold && !(fontDef.styleStrategy & QFont::NoAntialias))); CGContextSetShouldSmoothFonts(ctx, aa); CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx); @@ -696,12 +785,19 @@ QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPo return im; } -void QCoreTextFontEngine::recalcAdvances(int numGlyphs, QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const +void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const { - Q_ASSERT(false); - Q_UNUSED(numGlyphs); - Q_UNUSED(glyphs); - Q_UNUSED(flags); + int i, numGlyphs = glyphs->numGlyphs; + QVarLengthArray cgGlyphs(numGlyphs); + + for (i = 0; i < numGlyphs; ++i) { + if (glyphs->glyphs[i] & 0xff000000) + cgGlyphs[i] = 0; + else + cgGlyphs[i] = glyphs->glyphs[i]; + } + + loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, numGlyphs, flags, fontDef); } QFontEngine::FaceId QCoreTextFontEngine::faceId() const @@ -711,36 +807,36 @@ QFontEngine::FaceId QCoreTextFontEngine::faceId() const bool QCoreTextFontEngine::canRender(const QChar *string, int len) { - QCFType retFont = CTFontCreateForString(ctfont, - QCFType(CFStringCreateWithCharactersNoCopy(0, - reinterpret_cast(string), - len, kCFAllocatorNull)), - CFRangeMake(0, len)); - return retFont != 0; - return false; -} - - bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const - { - QCFType table = CTFontCopyTable(ctfont, tag, 0); - if (!table || !length) - return false; - CFIndex tableLength = CFDataGetLength(table); - int availableLength = *length; - *length = tableLength; - if (buffer) { - if (tableLength > availableLength) - return false; - CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer); - } - return true; - } + QVarLengthArray cgGlyphs(len); + return CTFontGetGlyphsForCharacters(ctfont, (const UniChar *) string, cgGlyphs.data(), len); +} + +bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const +{ + QCFType table = CTFontCopyTable(ctfont, tag, 0); + if (!table || !length) + return false; + CFIndex tableLength = CFDataGetLength(table); + int availableLength = *length; + *length = tableLength; + if (buffer) { + if (tableLength > availableLength) + return false; + CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer); + } + return true; +} void QCoreTextFontEngine::getUnscaledGlyph(glyph_t, QPainterPath *, glyph_metrics_t *) { // ### } +QFixed QCoreTextFontEngine::emSquareSize() const +{ + return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont))); +} + QT_END_NAMESPACE #endif// !defined(Q_WS_MAC) || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) diff --git a/src/gui/text/qfontengine_coretext_p.h b/src/gui/text/qfontengine_coretext_p.h index 7d17aef..1503c3f 100644 --- a/src/gui/text/qfontengine_coretext_p.h +++ b/src/gui/text/qfontengine_coretext_p.h @@ -46,15 +46,17 @@ #if !defined(Q_WS_MAC) || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) +class QRawFontPrivate; class QCoreTextFontEngineMulti; class QCoreTextFontEngine : public QFontEngine { public: - QCoreTextFontEngine(CTFontRef font, const QFontDef &def, - QCoreTextFontEngineMulti *multiEngine = 0); + QCoreTextFontEngine(CTFontRef font, const QFontDef &def); + QCoreTextFontEngine(CGFontRef font, const QFontDef &def); ~QCoreTextFontEngine(); + virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; - virtual void recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const; + virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const; virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs); virtual glyph_metrics_t boundingBox(glyph_t glyph); @@ -87,23 +89,29 @@ public: virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, int margin, const QTransform &t); virtual qreal minRightBearing() const; virtual qreal minLeftBearing() const; - virtual QFont createExplicitFont() const; + virtual QFixed emSquareSize() const; private: + friend class QRawFontPrivate; + + void init(); QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int margin, bool colorful); CTFontRef ctfont; CGFontRef cgFont; - QCoreTextFontEngineMulti *parentEngine; int synthesisFlags; CGAffineTransform transform; + QFixed avgCharWidth; + qreal ctMaxCharWidth; + qreal ctMinLeftBearing; + qreal ctMinRightBearing; friend class QCoreTextFontEngineMulti; - int antialiasing_threshold; }; class QCoreTextFontEngineMulti : public QFontEngineMulti { public: QCoreTextFontEngineMulti(const QCFString &name, const QFontDef &fontDef, bool kerning); + QCoreTextFontEngineMulti(CGFontRef cgFontRef, const QFontDef &fontDef, bool kerning); ~QCoreTextFontEngineMulti(); virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, @@ -112,19 +120,16 @@ public: QTextEngine::ShaperFlags flags, unsigned short *logClusters, const HB_CharAttributes *charAttributes) const; - - virtual void recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const; - virtual void doKerning(int , QGlyphLayout *, QTextEngine::ShaperFlags) const; - virtual const char *name() const { return "CoreText"; } protected: virtual void loadEngine(int at); private: + void init(bool kerning); inline const QCoreTextFontEngine *engineAt(int i) const { return static_cast(engines.at(i)); } - uint fontIndexForFont(CTFontRef id) const; + uint fontIndexForFont(CTFontRef font) const; CTFontRef ctfont; mutable QCFType attributeDict; CGAffineTransform transform; diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index ffdaaa7..8f2da9b 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -200,9 +200,10 @@ HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 p * Returns the freetype face or 0 in case of an empty file or any other problems * (like not being able to open the file) */ -QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id) +QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id, + const QByteArray &fontData) { - if (face_id.filename.isEmpty()) + if (face_id.filename.isEmpty() && fontData.isEmpty()) return 0; QtFreetypeData *freetypeData = qt_getFreetypeData(); @@ -215,21 +216,25 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id) } else { QScopedPointer newFreetype(new QFreetypeFace); FT_Face face; - QFile file(QString::fromUtf8(face_id.filename)); - if (face_id.filename.startsWith(":qmemoryfonts/")) { - // from qfontdatabase.cpp - extern QByteArray qt_fontdata_from_index(int); - QByteArray idx = face_id.filename; - idx.remove(0, 14); // remove ':qmemoryfonts/' - bool ok = false; - newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok)); - if (!ok) - newFreetype->fontData = QByteArray(); - } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) { - if (!file.open(QIODevice::ReadOnly)) { - return 0; + if (!face_id.filename.isEmpty()) { + QFile file(QString::fromUtf8(face_id.filename)); + if (face_id.filename.startsWith(":qmemoryfonts/")) { + // from qfontdatabase.cpp + extern QByteArray qt_fontdata_from_index(int); + QByteArray idx = face_id.filename; + idx.remove(0, 14); // remove ':qmemoryfonts/' + bool ok = false; + newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok)); + if (!ok) + newFreetype->fontData = QByteArray(); + } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) { + if (!file.open(QIODevice::ReadOnly)) { + return 0; + } + newFreetype->fontData = file.readAll(); } - newFreetype->fontData = file.readAll(); + } else { + newFreetype->fontData = fontData; } if (!newFreetype->fontData.isEmpty()) { if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) { @@ -651,8 +656,21 @@ void QFontEngineFT::freeGlyphSets() freeServerGlyphSet(transformedGlyphSets.at(i).id); } -bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format) +bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, + const QByteArray &fontData) { + return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData)); +} + +bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, + QFreetypeFace *freetypeFace) +{ + freetype = freetypeFace; + if (!freetype) { + xsize = 0; + ysize = 0; + return false; + } defaultFormat = format; this->antialias = antialias; @@ -664,12 +682,6 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format) glyphFormat = QFontEngineGlyphCache::Raster_RGBMask; face_id = faceId; - freetype = QFreetypeFace::getFace(face_id); - if (!freetype) { - xsize = 0; - ysize = 0; - return false; - } symbol = freetype->symbol_map != 0; PS_FontInfoRec psrec; @@ -791,6 +803,106 @@ int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags, return load_flags; } +QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph, GlyphFormat format) const +{ + Glyph *g = set->getGlyph(glyph); + if (g && g->format == format) + return g; + + bool hsubpixel = false; + int vfactor = 1; + int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor); + + // apply our matrix to this, but note that the metrics will not be affected by this. + FT_Face face = lockFace(); + FT_Matrix matrix = this->matrix; + FT_Matrix_Multiply(&set->transformationMatrix, &matrix); + FT_Set_Transform(face, &matrix, 0); + freetype->matrix = matrix; + + bool transform = matrix.xx != 0x10000 || matrix.yy != 0x10000 || matrix.xy != 0 || matrix.yx != 0; + if (transform) + load_flags |= FT_LOAD_NO_BITMAP; + + FT_Error err = FT_Load_Glyph(face, glyph, load_flags); + if (err && (load_flags & FT_LOAD_NO_BITMAP)) { + load_flags &= ~FT_LOAD_NO_BITMAP; + err = FT_Load_Glyph(face, glyph, load_flags); + } + if (err == FT_Err_Too_Few_Arguments) { + // this is an error in the bytecode interpreter, just try to run without it + load_flags |= FT_LOAD_FORCE_AUTOHINT; + err = FT_Load_Glyph(face, glyph, load_flags); + } + if (err != FT_Err_Ok) + qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph); + + unlockFace(); + if (set->outline_drawing) + return 0; + + if (!g) { + g = new Glyph; + g->uploadedToServer = false; + g->data = 0; + } + + FT_GlyphSlot slot = face->glyph; + if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot); + int left = slot->metrics.horiBearingX; + int right = slot->metrics.horiBearingX + slot->metrics.width; + int top = slot->metrics.horiBearingY; + int bottom = slot->metrics.horiBearingY - slot->metrics.height; + if (transform && slot->format != FT_GLYPH_FORMAT_BITMAP) { // freetype doesn't apply the transformation on the metrics + int l, r, t, b; + FT_Vector vector; + vector.x = left; + vector.y = top; + FT_Vector_Transform(&vector, &matrix); + l = r = vector.x; + t = b = vector.y; + vector.x = right; + vector.y = top; + FT_Vector_Transform(&vector, &matrix); + if (l > vector.x) l = vector.x; + if (r < vector.x) r = vector.x; + if (t < vector.y) t = vector.y; + if (b > vector.y) b = vector.y; + vector.x = right; + vector.y = bottom; + FT_Vector_Transform(&vector, &matrix); + if (l > vector.x) l = vector.x; + if (r < vector.x) r = vector.x; + if (t < vector.y) t = vector.y; + if (b > vector.y) b = vector.y; + vector.x = left; + vector.y = bottom; + FT_Vector_Transform(&vector, &matrix); + if (l > vector.x) l = vector.x; + if (r < vector.x) r = vector.x; + if (t < vector.y) t = vector.y; + if (b > vector.y) b = vector.y; + left = l; + right = r; + top = t; + bottom = b; + } + left = FLOOR(left); + right = CEIL(right); + bottom = FLOOR(bottom); + top = CEIL(top); + + g->linearAdvance = face->glyph->linearHoriAdvance >> 10; + g->width = TRUNC(right-left); + g->height = TRUNC(top-bottom); + g->x = TRUNC(left); + g->y = TRUNC(top); + g->advance = TRUNC(ROUND(face->glyph->advance.x)); + g->format = Format_None; + + return g; +} + QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, QFixed subPixelPosition, GlyphFormat format, @@ -1511,7 +1623,7 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs mtx->lock(); } - if (FcCharSetHasChar(freetype->charset, uc)) { + if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) { #else if (false) { #endif @@ -1546,7 +1658,7 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs mtx->lock(); } - if (FcCharSetHasChar(freetype->charset, uc)) + if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc)) #endif { redo: diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index 451d26e..887efed 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -74,6 +74,8 @@ QT_BEGIN_NAMESPACE +class QFontEngineFTRawFont; + /* * This struct represents one font file on disk (like Arial.ttf) and is shared between all the font engines * that show this font file (at different pixel sizes). @@ -84,7 +86,8 @@ struct QFreetypeFace QFontEngine::Properties properties() const; bool getSfntTable(uint tag, uchar *buffer, uint *length) const; - static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id); + static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id, + const QByteArray &fontData = QByteArray()); void release(const QFontEngine::FaceId &face_id); // locks the struct for usage. Any read/write operations require locking. @@ -119,6 +122,7 @@ struct QFreetypeFace static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool = false); private: + friend class QFontEngineFTRawFont; friend class QScopedPointerDeleter; QFreetypeFace() : _lock(QMutex::Recursive) {} ~QFreetypeFace() {} @@ -300,7 +304,10 @@ private: QFontEngineFT(const QFontDef &fd); virtual ~QFontEngineFT(); - bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat = Format_None); + bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat = Format_None, + const QByteArray &fontData = QByteArray()); + bool init(FaceId faceId, bool antialias, GlyphFormat format, + QFreetypeFace *freetypeFace); virtual HB_Error getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints); @@ -312,6 +319,7 @@ private: }; void setDefaultHintStyle(HintStyle style); + HintStyle defaultHintStyle() const { return default_hint_style; } protected: void freeGlyphSets(); @@ -335,6 +343,9 @@ protected: bool embeddedbitmap; private: + friend class QFontEngineFTRawFont; + + QFontEngineFT::Glyph *loadGlyphMetrics(QGlyphSet *set, uint glyph, GlyphFormat format) const; int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const; GlyphFormat defaultFormat; diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm index 7751bbe..673a7c8 100644 --- a/src/gui/text/qfontengine_mac.mm +++ b/src/gui/text/qfontengine_mac.mm @@ -922,27 +922,6 @@ static void addGlyphsToPathHelper(ATSUStyle style, glyph_t *glyphs, QFixedPoint DisposeATSCubicClosePathUPP(closePath); } -QFont QFontEngineMac::createExplicitFont() const -{ - FMFont fmFont = FMGetFontFromATSFontRef(fontID); - - FMFontFamily fmFamily; - FMFontStyle fmStyle; - QString familyName; - if (!FMGetFontFamilyInstanceFromFont(fmFont, &fmFamily, &fmStyle)) { - ATSFontFamilyRef familyRef = FMGetATSFontFamilyRefFromFontFamily(fmFamily); - QCFString cfFamilyName;; - ATSFontFamilyGetName(familyRef, kATSOptionFlagsDefault, &cfFamilyName); - familyName = cfFamilyName; - } else { - QCFString cfFontName; - ATSFontGetName(fontID, kATSOptionFlagsDefault, &cfFontName); - familyName = cfFontName; - } - - return createExplicitFontWithName(familyName); -} - void QFontEngineMac::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags) { diff --git a/src/gui/text/qfontengine_mac_p.h b/src/gui/text/qfontengine_mac_p.h index 6967348..385fa83 100644 --- a/src/gui/text/qfontengine_mac_p.h +++ b/src/gui/text/qfontengine_mac_p.h @@ -66,8 +66,6 @@ public: virtual qreal maxCharWidth() const; virtual QFixed averageCharWidth() const; - virtual QFont createExplicitFont() const; - virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags); diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 7b29993..5b39fd3 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -185,9 +185,6 @@ public: virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags); - /* Creates a QFont object to represent this particular QFontEngine */ - virtual QFont createExplicitFont() const; - void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags, QVarLengthArray &glyphs_out, QVarLengthArray &positions); @@ -276,7 +273,6 @@ public: int glyphFormat; protected: - QFont createExplicitFontWithName(const QString &familyName) const; static const QVector &grayPalette(); QFixed lastRightBearing(const QGlyphLayout &glyphs, bool round = false); @@ -431,6 +427,7 @@ public: protected: friend class QPSPrintEnginePrivate; friend class QPSPrintEngineFontMulti; + friend class QRawFont; virtual void loadEngine(int at) = 0; QVector engines; }; diff --git a/src/gui/text/qfontengine_x11_p.h b/src/gui/text/qfontengine_x11_p.h index 2a4a9cd..ad68fac 100644 --- a/src/gui/text/qfontengine_x11_p.h +++ b/src/gui/text/qfontengine_x11_p.h @@ -157,6 +157,7 @@ private: class Q_GUI_EXPORT QFontEngineX11FT : public QFontEngineFT { public: + explicit QFontEngineX11FT(const QFontDef &fontDef) : QFontEngineFT(fontDef) {} explicit QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int screen); ~QFontEngineX11FT(); diff --git a/src/gui/text/qfontenginedirectwrite.cpp b/src/gui/text/qfontenginedirectwrite.cpp index af5bab2..f0a3644 100644 --- a/src/gui/text/qfontenginedirectwrite.cpp +++ b/src/gui/text/qfontenginedirectwrite.cpp @@ -170,17 +170,12 @@ namespace { } -QFontEngineDirectWrite::QFontEngineDirectWrite(const QString &name, - IDWriteFactory *directWriteFactory, - IDWriteGdiInterop *directWriteGdiInterop, - IDWriteFont *directWriteFont, +QFontEngineDirectWrite::QFontEngineDirectWrite(IDWriteFactory *directWriteFactory, + IDWriteFontFace *directWriteFontFace, qreal pixelSize) - : m_name(name) - , m_directWriteFont(directWriteFont) - , m_directWriteFontFace(0) + : m_directWriteFontFace(directWriteFontFace) , m_directWriteFactory(directWriteFactory) , m_directWriteBitmapRenderTarget(0) - , m_directWriteGdiInterop(directWriteGdiInterop) , m_lineThickness(-1) , m_unitsPerEm(-1) , m_ascent(-1) @@ -188,24 +183,17 @@ QFontEngineDirectWrite::QFontEngineDirectWrite(const QString &name, , m_xHeight(-1) , m_lineGap(-1) { - m_directWriteFont->AddRef(); m_directWriteFactory->AddRef(); - m_directWriteGdiInterop->AddRef(); + m_directWriteFontFace->AddRef(); fontDef.pixelSize = pixelSize; - - HRESULT hr = m_directWriteFont->CreateFontFace(&m_directWriteFontFace); - if (FAILED(hr)) - qErrnoWarning("QFontEngineDirectWrite: CreateFontFace failed"); - collectMetrics(); } QFontEngineDirectWrite::~QFontEngineDirectWrite() { - m_directWriteFont->Release(); m_directWriteFactory->Release(); - m_directWriteGdiInterop->Release(); + m_directWriteFontFace->Release(); if (m_directWriteBitmapRenderTarget != 0) m_directWriteBitmapRenderTarget->Release(); @@ -213,10 +201,10 @@ QFontEngineDirectWrite::~QFontEngineDirectWrite() void QFontEngineDirectWrite::collectMetrics() { - if (m_directWriteFont != 0) { + if (m_directWriteFontFace != 0) { DWRITE_FONT_METRICS metrics; - m_directWriteFont->GetMetrics(&metrics); + m_directWriteFontFace->GetMetrics(&metrics); m_unitsPerEm = metrics.designUnitsPerEm; m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); @@ -616,19 +604,25 @@ const char *QFontEngineDirectWrite::name() const bool QFontEngineDirectWrite::canRender(const QChar *string, int len) { - for (int i=0; iHasCharacter(codePoint, &exists); - if (FAILED(hr)) { - qErrnoWarning("QFontEngineDirectWrite::canRender: HasCharacter failed"); - return false; - } else if (!exists) { - return false; + QVarLengthArray codePoints(len); + int actualLength = 0; + for (int i=0; i glyphIndices(actualLength); + HRESULT hr = m_directWriteFontFace->GetGlyphIndices(codePoints.data(), actualLength, + glyphIndices.data()); + if (FAILED(hr)) { + qErrnoWarning(hr, "QFontEngineDirectWrite::canRender: GetGlyphIndices failed"); + return false; + } else { + for (int i=0; iglyphIndexes == other.d->glyphIndexes && d->glyphPositions == other.d->glyphPositions + && d->overline == other.d->overline + && d->underline == other.d->underline + && d->strikeOut == other.d->strikeOut && d->font == other.d->font)); } @@ -171,18 +184,17 @@ QGlyphs &QGlyphs::operator+=(const QGlyphs &other) \sa setFont() */ -QFont QGlyphs::font() const +QRawFont QGlyphs::font() const { return d->font; } /*! - Sets the font in which to look up the glyph indexes to \a font. This must be an explicitly - resolvable font which defines glyphs for the specified glyph indexes. + Sets the font in which to look up the glyph indexes to \a font. \sa font(), setGlyphIndexes() */ -void QGlyphs::setFont(const QFont &font) +void QGlyphs::setFont(const QRawFont &font) { detach(); d->font = font; @@ -234,7 +246,78 @@ void QGlyphs::clear() detach(); d->glyphPositions = QVector(); d->glyphIndexes = QVector(); - d->font = QFont(); + d->font = QRawFont(); + d->strikeOut = false; + d->overline = false; + d->underline = false; +} + +/*! + Returns true if this QGlyphs should be painted with an overline decoration. + + \sa setOverline() +*/ +bool QGlyphs::overline() const +{ + return d->overline; +} + +/*! + Indicates that this QGlyphs should be painted with an overline decoration if \a overline is true. + Otherwise the QGlyphs should be painted with no overline decoration. + + \sa overline() +*/ +void QGlyphs::setOverline(bool overline) +{ + detach(); + d->overline = overline; +} + +/*! + Returns true if this QGlyphs should be painted with an underline decoration. + + \sa setUnderline() +*/ +bool QGlyphs::underline() const +{ + return d->underline; +} + +/*! + Indicates that this QGlyphs should be painted with an underline decoration if \a underline is + true. Otherwise the QGlyphs should be painted with no underline decoration. + + \sa underline() +*/ +void QGlyphs::setUnderline(bool underline) +{ + detach(); + d->underline = underline; +} + +/*! + Returns true if this QGlyphs should be painted with a strike out decoration. + + \sa setStrikeOut() +*/ +bool QGlyphs::strikeOut() const +{ + return d->strikeOut; +} + +/*! + Indicates that this QGlyphs should be painted with an strike out decoration if \a strikeOut is + true. Otherwise the QGlyphs should be painted with no strike out decoration. + + \sa strikeOut() +*/ +void QGlyphs::setStrikeOut(bool strikeOut) +{ + detach(); + d->strikeOut = strikeOut; } QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qglyphs.h b/src/gui/text/qglyphs.h index 5f37136..4d7dcaf 100644 --- a/src/gui/text/qglyphs.h +++ b/src/gui/text/qglyphs.h @@ -45,7 +45,9 @@ #include #include #include -#include +#include + +#if !defined(QT_NO_RAWFONT) QT_BEGIN_HEADER @@ -61,8 +63,8 @@ public: QGlyphs(const QGlyphs &other); ~QGlyphs(); - QFont font() const; - void setFont(const QFont &font); + QRawFont font() const; + void setFont(const QRawFont &font); QVector glyphIndexes() const; void setGlyphIndexes(const QVector &glyphIndexes); @@ -76,6 +78,15 @@ public: bool operator==(const QGlyphs &other) const; bool operator!=(const QGlyphs &other) const; + void setOverline(bool overline); + bool overline() const; + + void setUnderline(bool underline); + bool underline() const; + + void setStrikeOut(bool strikeOut); + bool strikeOut() const; + private: friend class QGlyphsPrivate; friend class QTextLine; @@ -85,12 +96,12 @@ private: void detach(); QExplicitlySharedDataPointer d; - }; QT_END_NAMESPACE QT_END_HEADER +#endif // QT_NO_RAWFONT #endif // QGLYPHS_H diff --git a/src/gui/text/qglyphs_p.h b/src/gui/text/qglyphs_p.h index c632e2f..944f777 100644 --- a/src/gui/text/qglyphs_p.h +++ b/src/gui/text/qglyphs_p.h @@ -53,8 +53,12 @@ // We mean it. // -#include #include "qglyphs.h" +#include "qrawfont.h" + +#include + +#if !defined(QT_NO_RAWFONT) QT_BEGIN_HEADER @@ -64,17 +68,30 @@ class QGlyphsPrivate: public QSharedData { public: QGlyphsPrivate() + : overline(false) + , underline(false) + , strikeOut(false) { } QGlyphsPrivate(const QGlyphsPrivate &other) - : QSharedData(other), glyphIndexes(other.glyphIndexes), glyphPositions(other.glyphPositions), font(other.font) + : QSharedData(other) + , glyphIndexes(other.glyphIndexes) + , glyphPositions(other.glyphPositions) + , font(other.font) + , overline(other.overline) + , underline(other.underline) + , strikeOut(other.strikeOut) { } QVector glyphIndexes; QVector glyphPositions; - QFont font; + QRawFont font; + + uint overline : 1; + uint underline : 1; + uint strikeOut : 1; }; QT_END_NAMESPACE @@ -82,3 +99,5 @@ QT_END_NAMESPACE QT_END_HEADER #endif // QGLYPHS_P_H + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp new file mode 100644 index 0000000..4a715c2 --- /dev/null +++ b/src/gui/text/qrawfont.cpp @@ -0,0 +1,612 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglobal.h" + +#if !defined(QT_NO_RAWFONT) + +#include "qrawfont.h" +#include "qrawfont_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QRawFont + \brief The QRawFont class provides access to a single physical instance of a font. + \since 4.8 + + \ingroup text + \mainclass + + \note QRawFont is a low level class. For most purposes QFont is a more appropriate class. + + Most commonly, when presenting text in a user interface, the exact fonts used + to render the characters is to some extent unknown. This can be the case for several + reasons: For instance, the actual, physical fonts present on the target system could be + unexpected to the developers, or the text could contain user selected styles, sizes or + writing systems that are not supported by font chosen in the code. + + Therefore, Qt's QFont class really represents a query for fonts. When text is interpreted, + Qt will do its best to match the text to the query, but depending on the support, different + fonts can be used behind the scenes. + + For most use cases, this is both expected and necessary, as it minimizes the possibility of + text in the user interface being undisplayable. In some cases, however, more direct control + over the process might be useful. It is for these use cases the QRawFont class exists. + + A QRawFont object represents a single, physical instance of a given font in a given pixel size. + I.e. in the typical case it represents a set of TrueType or OpenType font tables and uses a + user specified pixel size to convert metrics into logical pixel units. In can be used in + combination with the QGlyphs class to draw specific glyph indexes at specific positions, and + also have accessors to some relevant data in the physical font. + + QRawFont only provides support for the main font technologies: GDI and DirectWrite on Windows + platforms, FreeType on Symbian and Linux platforms and CoreText on Mac OS X. For other + font back-ends, the APIs will be disabled. + + QRawFont can be constructed in a number of ways: + \list + \o \l It can be constructed by calling QTextLayout::glyphs() or QTextFragment::glyphs(). The + returned QGlyphs objects will contain QRawFont objects which represent the actual fonts + used to render each portion of the text. + \o \l It can be constructed by passing a QFont object to QRawFont::fromFont(). The function + will return a QRawFont object representing the font that will be selected as response to + the QFont query and the selected writing system. + \o \l It can be constructed by passing a file name or QByteArray directly to the QRawFont + constructor, or by calling loadFromFile() or loadFromData(). In this case, the + font will not be registered in QFontDatabase, and it will not be available as part of + regular font selection. + \endlist + + QRawFont is considered local to the thread in which it is constructed (either using a + constructor, or by calling loadFromData() or loadFromFile()). The QRawFont cannot be moved to a + different thread, but will have to be recreated in the thread in question. + + \note For the requirement of caching glyph indexes and font selections for static text to avoid + reshaping and relayouting in the inner loop of an application, a better choice is the QStaticText + class, since it optimizes the memory cost of the cache and also provides the possibility of paint + engine specific caches for an additional speed-up. +*/ + +/*! + \enum QRawFont::AntialiasingType + + This enum represents the different ways a glyph can be rasterized in the function + alphaMapForGlyph(). + + \value PixelAntialiasing Will rasterize by measuring the coverage of the shape on whole pixels. + The returned image contains the alpha values of each pixel based on the coverage of + the glyph shape. + \value SubPixelAntialiasing Will rasterize by measuring the coverage of each subpixel, + returning a separate alpha value for each of the red, green and blue components of + each pixel. +*/ + +/*! + Constructs an invalid QRawFont. +*/ +QRawFont::QRawFont() + : d(new QRawFontPrivate) +{ +} + +/*! + Constructs a QRawFont representing the font contained in the file referenced by \a fileName, + with \a pixelSize size in pixels, and the selected \a hintingPreference. + + \note The referenced file must contain a TrueType or OpenType font. +*/ +QRawFont::QRawFont(const QString &fileName, + int pixelSize, + QFont::HintingPreference hintingPreference) + : d(new QRawFontPrivate) +{ + loadFromFile(fileName, pixelSize, hintingPreference); +} + +/*! + Constructs a QRawFont representing the font contained in \a fontData. + + \note The data must contain a TrueType or OpenType font. +*/ +QRawFont::QRawFont(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference) + : d(new QRawFontPrivate) +{ + loadFromData(fontData, pixelSize, hintingPreference); +} + +/*! + Creates a QRawFont which is a copy of \a other. +*/ +QRawFont::QRawFont(const QRawFont &other) +{ + d = other.d; +} + +/*! + Destroys the QRawFont +*/ +QRawFont::~QRawFont() +{ +} + +/*! + Assigns \a other to this QRawFont. +*/ +QRawFont &QRawFont::operator=(const QRawFont &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if the QRawFont is valid and false otherwise. +*/ +bool QRawFont::isValid() const +{ + Q_ASSERT(d->thread == 0 || d->thread == QThread::currentThread()); + return d->fontEngine != 0; +} + +/*! + Replaces the current QRawFont with the contents of the file references by \a fileName. + + The file must reference a TrueType or OpenType font. + + \sa loadFromData() +*/ +void QRawFont::loadFromFile(const QString &fileName, + int pixelSize, + QFont::HintingPreference hintingPreference) +{ + QFile file(fileName); + if (file.open(QIODevice::ReadOnly)) + loadFromData(file.readAll(), pixelSize, hintingPreference); +} + +/*! + Replaces the current QRawFont with the contents of \a fontData. + + The \a fontData must contain a TrueType or OpenType font. + + \sa loadFromFile() +*/ +void QRawFont::loadFromData(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference) +{ + detach(); + d->cleanUp(); + d->hintingPreference = hintingPreference; + d->thread = QThread::currentThread(); + d->platformLoadFromData(fontData, pixelSize, hintingPreference); +} + +/*! + This function returns a rasterized image of the glyph at a given \a glyphIndex in the underlying + font, if the QRawFont is valid, otherwise it will return an invalid QImage. + + If \a antialiasingType is set to QRawFont::SubPixelAntialiasing, then the resulting image will be + in QImage::Format_RGB32 and the RGB values of each pixel will represent the subpixel opacities of + the pixel in the rasterization of the glyph. Otherwise, the image will be in the format of + QImage::Format_A8 and each pixel will contain the opacity of the pixel in the rasterization. + + \sa pathForGlyph(), QPainter::drawGlyphs() +*/ +QImage QRawFont::alphaMapForGlyph(quint32 glyphIndex, AntialiasingType antialiasingType, + const QTransform &transform) const +{ + if (!isValid()) + return QImage(); + + if (antialiasingType == SubPixelAntialiasing) + return d->fontEngine->alphaRGBMapForGlyph(glyphIndex, QFixed(), 0, transform); + else + return d->fontEngine->alphaMapForGlyph(glyphIndex, QFixed(), transform); +} + +/*! + This function returns the shape of the glyph at a given \a glyphIndex in the underlying font + if the QRawFont is valid. Otherwise, it returns an empty QPainterPath. + + The returned glyph will always be unhinted. + + \sa alphaMapForGlyph(), QPainterPath::addText() +*/ +QPainterPath QRawFont::pathForGlyph(quint32 glyphIndex) const +{ + if (!isValid()) + return QPainterPath(); + + QFixedPoint position; + QPainterPath path; + d->fontEngine->addGlyphsToPath(&glyphIndex, &position, 1, &path, 0); + return path; +} + +/*! + Returns true if this QRawFont is equal to \a other. Otherwise, returns false. +*/ +bool QRawFont::operator==(const QRawFont &other) const +{ + return d->fontEngine == other.d->fontEngine; +} + +/*! + Returns the ascent of this QRawFont in pixel units. + + \sa QFontMetricsF::ascent() +*/ +qreal QRawFont::ascent() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->ascent().toReal(); +} + +/*! + Returns the descent of this QRawFont in pixel units. + + \sa QFontMetricsF::descent() +*/ +qreal QRawFont::descent() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->descent().toReal(); +} + +/*! + Returns the pixel size set for this QRawFont. The pixel size affects how glyphs are + rasterized, the size of glyphs returned by pathForGlyph(), and is used to convert + internal metrics from design units to logical pixel units. + + \sa setPixelSize() +*/ +int QRawFont::pixelSize() const +{ + if (!isValid()) + return -1; + + return d->fontEngine->fontDef.pixelSize; +} + +/*! + Returns the number of design units define the width and height of the em square + for this QRawFont. This value is used together with the pixel size when converting design metrics + to pixel units, as the internal metrics are specified in design units and the pixel size gives + the size of 1 em in pixels. + + \sa pixelSize(), setPixelSize() +*/ +qreal QRawFont::unitsPerEm() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->emSquareSize().toReal(); +} + +/*! + Returns the family name of this QRawFont. +*/ +QString QRawFont::familyName() const +{ + if (!isValid()) + return QString(); + + return d->fontEngine->fontDef.family; +} + +/*! + Returns the style of this QRawFont. + + \sa QFont::style() +*/ +QFont::Style QRawFont::style() const +{ + if (!isValid()) + return QFont::StyleNormal; + + return QFont::Style(d->fontEngine->fontDef.style); +} + +/*! + Returns the weight of this QRawFont. + + \sa QFont::weight() +*/ +int QRawFont::weight() const +{ + if (!isValid()) + return -1; + + return int(d->fontEngine->fontDef.weight); +} + +/*! + Converts a string of unicode points to glyph indexes using the CMAP table in the + underlying font. Note that in cases where there are other tables in the font that affect the + shaping of the text, the returned glyph indexes will not correctly represent the rendering + of the text. To get the correctly shaped text, you can use QTextLayout to lay out and shape the + text, and then call QTextLayout::glyphs() to get the set of glyph index list and QRawFont pairs. + + \sa advancesForGlyphIndexes(), QGlyphs, QTextLayout::glyphs(), QTextFragment::glyphs() +*/ +QVector QRawFont::glyphIndexesForString(const QString &text) const +{ + if (!isValid()) + return QVector(); + + int nglyphs = text.size(); + QVarLengthGlyphLayoutArray glyphs(nglyphs); + if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &nglyphs, + QTextEngine::GlyphIndicesOnly)) { + glyphs.resize(nglyphs); + if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &nglyphs, + QTextEngine::GlyphIndicesOnly)) { + Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); + return QVector(); + } + } + + QVector glyphIndexes; + for (int i=0; i QRawFont::advancesForGlyphIndexes(const QVector &glyphIndexes) const +{ + if (!isValid()) + return QVector(); + + int numGlyphs = glyphIndexes.size(); + QVarLengthGlyphLayoutArray glyphs(numGlyphs); + qMemCopy(glyphs.glyphs, glyphIndexes.data(), numGlyphs * sizeof(quint32)); + + d->fontEngine->recalcAdvances(&glyphs, 0); + + QVector advances; + for (int i=0; ihintingPreference; +} + +/*! + Retrieves the sfnt table named \a tagName from the underlying physical font, or an empty + byte array if no such table was found. The returned font table's byte order is Big Endian, like + the sfnt format specifies. The \a tagName must be four characters long and should be formatted + in the default endianness of the current platform. +*/ +QByteArray QRawFont::fontTable(const char *tagName) const +{ + if (!isValid()) + return QByteArray(); + + const quint32 *tagId = reinterpret_cast(tagName); + return d->fontEngine->getSfntTable(qToBigEndian(*tagId)); +} + +// From qfontdatabase.cpp +extern QList qt_determine_writing_systems_from_truetype_bits(quint32 unicodeRange[4], quint32 codePageRange[2]); + +/*! + Returns a list of writing systems supported by the font according to designer supplied + information in the font file. Please note that this does not guarantee support for a + specific unicode point in the font. You can use the supportsCharacter() to check support + for a single, specific character. + + \note The list is determined based on the unicode ranges and codepage ranges set in the font's + OS/2 table and requires such a table to be present in the underlying font file. + + \sa supportsCharacter() +*/ +QList QRawFont::supportedWritingSystems() const +{ + if (isValid()) { + QByteArray os2Table = fontTable("OS/2"); + if (!os2Table.isEmpty() && os2Table.size() > 86) { + char *data = os2Table.data(); + quint32 *bigEndianUnicodeRanges = reinterpret_cast(data + 42); + quint32 *bigEndianCodepageRanges = reinterpret_cast(data + 78); + + quint32 unicodeRanges[4]; + quint32 codepageRanges[2]; + + for (int i=0; i<4; ++i) { + if (i < 2) + codepageRanges[i] = qFromBigEndian(bigEndianCodepageRanges[i]); + unicodeRanges[i] = qFromBigEndian(bigEndianUnicodeRanges[i]); + } + + return qt_determine_writing_systems_from_truetype_bits(unicodeRanges, codepageRanges); + } + } + + return QList(); +} + +/*! + Returns true if the font has a glyph that corresponds to the given \a character. + + \sa supportedWritingSystems() +*/ +bool QRawFont::supportsCharacter(const QChar &character) const +{ + if (!isValid()) + return false; + + return d->fontEngine->canRender(&character, 1); +} + +/*! + Returns true if the font has a glyph that corresponds to the UCS-4 encoded character \a ucs4. + + \sa supportedWritingSystems() +*/ +bool QRawFont::supportsCharacter(quint32 ucs4) const +{ + if (!isValid()) + return false; + + QString str = QString::fromUcs4(&ucs4, 1); + return d->fontEngine->canRender(str.constData(), str.size()); +} + +// qfontdatabase.cpp +extern int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem); + +/*! + Fetches the physical representation based on a \a font query. The physical font returned is + the font that will be preferred by Qt in order to display text in the selected \a writingSystem. +*/ +QRawFont QRawFont::fromFont(const QFont &font, QFontDatabase::WritingSystem writingSystem) +{ +#if defined(Q_WS_MAC) + QTextLayout layout(QFontDatabase::writingSystemSample(writingSystem), font); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + QList list = layout.glyphs(); + if (list.size()) { + // Pick the one matches the family name we originally requested, + // if none of them match, just pick the first one + for (int i = 0; i < list.size(); i++) { + QGlyphs glyphs = list.at(i); + QRawFont rawfont = glyphs.font(); + if (rawfont.familyName() == font.family()) + return rawfont; + } + return list.at(0).font(); + } + return QRawFont(); +#else + QFontPrivate *font_d = QFontPrivate::get(font); + int script = qt_script_for_writing_system(writingSystem); + QFontEngine *fe = font_d->engineForScript(script); + + if (fe != 0 && fe->type() == QFontEngine::Multi) { + QFontEngineMulti *multiEngine = static_cast(fe); + fe = multiEngine->engine(0); + if (fe == 0) { + multiEngine->loadEngine(0); + fe = multiEngine->engine(0); + } + } + + if (fe != 0) { + QRawFont rawFont; + rawFont.d.data()->fontEngine = fe; + rawFont.d.data()->fontEngine->ref.ref(); + rawFont.d.data()->hintingPreference = font.hintingPreference(); + return rawFont; + } else { + return QRawFont(); + } +#endif +} + +/*! + Sets the pixel size with which this font should be rendered to \a pixelSize. +*/ +void QRawFont::setPixelSize(int pixelSize) +{ + detach(); + d->platformSetPixelSize(pixelSize); +} + +/*! + \internal +*/ +void QRawFont::detach() +{ + if (d->ref != 1) + d.detach(); +} + +/*! + \internal +*/ +void QRawFontPrivate::cleanUp() +{ + platformCleanUp(); + if (fontEngine != 0) { + fontEngine->ref.deref(); + if (fontEngine->cache_count == 0 && fontEngine->ref == 0) + delete fontEngine; + fontEngine = 0; + } + hintingPreference = QFont::PreferDefaultHinting; +} + +#endif // QT_NO_RAWFONT + +QT_END_NAMESPACE diff --git a/src/gui/text/qrawfont.h b/src/gui/text/qrawfont.h new file mode 100644 index 0000000..96dc838 --- /dev/null +++ b/src/gui/text/qrawfont.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRAWFONT_H +#define QRAWFONT_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(QT_NO_RAWFONT) + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QRawFontPrivate; +class Q_GUI_EXPORT QRawFont +{ +public: + enum AntialiasingType { + PixelAntialiasing, + SubPixelAntialiasing + }; + + QRawFont(); + QRawFont(const QString &fileName, + int pixelSize, + QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting); + QRawFont(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting); + QRawFont(const QRawFont &other); + ~QRawFont(); + + bool isValid() const; + + QRawFont &operator=(const QRawFont &other); + bool operator==(const QRawFont &other) const; + + QString familyName() const; + + QFont::Style style() const; + int weight() const; + + QVector glyphIndexesForString(const QString &text) const; + QVector advancesForGlyphIndexes(const QVector &glyphIndexes) const; + + QImage alphaMapForGlyph(quint32 glyphIndex, + AntialiasingType antialiasingType = SubPixelAntialiasing, + const QTransform &transform = QTransform()) const; + QPainterPath pathForGlyph(quint32 glyphIndex) const; + + void setPixelSize(int pixelSize); + int pixelSize() const; + + QFont::HintingPreference hintingPreference() const; + + qreal ascent() const; + qreal descent() const; + + qreal unitsPerEm() const; + + void loadFromFile(const QString &fileName, + int pixelSize, + QFont::HintingPreference hintingPreference); + + void loadFromData(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference); + + bool supportsCharacter(quint32 ucs4) const; + bool supportsCharacter(const QChar &character) const; + QList supportedWritingSystems() const; + + QByteArray fontTable(const char *tagName) const; + + static QRawFont fromFont(const QFont &font, + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Any); + +private: + friend class QRawFontPrivate; + + void detach(); + + QExplicitlySharedDataPointer d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_RAWFONT + +#endif // QRAWFONT_H diff --git a/src/gui/text/qrawfont_ft.cpp b/src/gui/text/qrawfont_ft.cpp new file mode 100644 index 0000000..eefbd92 --- /dev/null +++ b/src/gui/text/qrawfont_ft.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#if !defined(QT_NO_RAWFONT) + +#include "qrawfont_p.h" +#include "qfontengine_ft_p.h" + +#if defined(Q_WS_X11) +# include "qfontengine_x11_p.h" +#endif + +QT_BEGIN_NAMESPACE + +class QFontEngineFTRawFont + +#if defined(Q_WS_X11) + : public QFontEngineX11FT +#else + : public QFontEngineFT +#endif + +{ +public: + QFontEngineFTRawFont(const QFontDef &fontDef) +#if defined(Q_WS_X11) + : QFontEngineX11FT(fontDef) +#else + : QFontEngineFT(fontDef) +#endif + { + } + + void updateFamilyNameAndStyle() + { + fontDef.family = QString::fromAscii(freetype->face->family_name); + + if (freetype->face->style_flags & FT_STYLE_FLAG_ITALIC) + fontDef.style = QFont::StyleItalic; + + if (freetype->face->style_flags & FT_STYLE_FLAG_BOLD) + fontDef.weight = QFont::Bold; + } + + bool initFromData(const QByteArray &fontData) + { + FaceId faceId; + faceId.filename = ""; + faceId.index = 0; + + return init(faceId, true, Format_None, fontData); + } + + bool initFromFontEngine(QFontEngine *oldFontEngine) + { + QFontEngineFT *fe = static_cast(oldFontEngine); + + // Increase the reference of this QFreetypeFace since one more QFontEngineFT + // will be using it + fe->freetype->ref.ref(); + if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype)) + return false; + + default_load_flags = fe->default_load_flags; + default_hint_style = fe->default_hint_style; + antialias = fe->antialias; + transform = fe->transform; + embolden = fe->embolden; + subpixelType = fe->subpixelType; + lcdFilterType = fe->lcdFilterType; + canUploadGlyphsToServer = fe->canUploadGlyphsToServer; + embeddedbitmap = fe->embeddedbitmap; + +#if defined(Q_WS_X11) + xglyph_format = static_cast(fe)->xglyph_format; +#endif + return true; + } +}; + + +void QRawFontPrivate::platformCleanUp() +{ + // Font engine handles all resources +} + +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize, + QFont::HintingPreference hintingPreference) +{ + Q_ASSERT(fontEngine == 0); + + QFontDef fontDef; + fontDef.pixelSize = pixelSize; + + QFontEngineFTRawFont *fe = new QFontEngineFTRawFont(fontDef); + if (!fe->initFromData(fontData)) { + delete fe; + return; + } + + fe->updateFamilyNameAndStyle(); + + switch (hintingPreference) { + case QFont::PreferNoHinting: + fe->setDefaultHintStyle(QFontEngineFT::HintNone); + break; + case QFont::PreferFullHinting: + fe->setDefaultHintStyle(QFontEngineFT::HintFull); + break; + case QFont::PreferVerticalHinting: + fe->setDefaultHintStyle(QFontEngineFT::HintLight); + break; + default: + // Leave it as it is + break; + } + + fontEngine = fe; + fontEngine->ref.ref(); +} + +void QRawFontPrivate::platformSetPixelSize(int pixelSize) +{ + if (fontEngine == NULL) + return; + + QFontEngine *oldFontEngine = fontEngine; + + QFontDef fontDef; + fontDef.pixelSize = pixelSize; + QFontEngineFTRawFont *fe = new QFontEngineFTRawFont(fontDef); + if (!fe->initFromFontEngine(oldFontEngine)) { + delete fe; + return; + } + + fontEngine = fe; + fontEngine->fontDef = oldFontEngine->fontDef; + fontEngine->fontDef.pixelSize = pixelSize; + fontEngine->ref.ref(); + Q_ASSERT(fontEngine != oldFontEngine); + oldFontEngine->ref.deref(); + if (oldFontEngine->cache_count == 0 && oldFontEngine->ref == 0) + delete oldFontEngine; +} + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qrawfont_mac.cpp b/src/gui/text/qrawfont_mac.cpp new file mode 100644 index 0000000..56005c6 --- /dev/null +++ b/src/gui/text/qrawfont_mac.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#if !defined(QT_NO_RAWFONT) + +#include "qrawfont_p.h" +#include "qfontengine_coretext_p.h" + +QT_BEGIN_NAMESPACE + +void QRawFontPrivate::platformCleanUp() +{ +} + +extern int qt_defaultDpi(); + +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference) +{ + // Mac OS X ignores it + Q_UNUSED(hintingPreference); + + QCFType dataProvider = CGDataProviderCreateWithData(NULL, + fontData.constData(), fontData.size(), NULL); + + CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider); + + if (cgFont == NULL) { + qWarning("QRawFont::platformLoadFromData: CGFontCreateWithDataProvider failed"); + } else { + QFontDef def; + def.pixelSize = pixelSize; + def.pointSize = pixelSize * 72.0 / qt_defaultDpi(); + fontEngine = new QCoreTextFontEngine(cgFont, def); + CFRelease(cgFont); + fontEngine->ref.ref(); + } +} + +void QRawFontPrivate::platformSetPixelSize(int pixelSize) +{ + if (fontEngine == NULL) + return; + + QFontEngine *oldFontEngine = fontEngine; + + QFontDef fontDef = oldFontEngine->fontDef; + fontDef.pixelSize = pixelSize; + fontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi(); + + QCoreTextFontEngine *ctFontEngine = static_cast(oldFontEngine); + Q_ASSERT(ctFontEngine->cgFont); + + fontEngine = new QCoreTextFontEngine(ctFontEngine->cgFont, fontDef); + fontEngine->ref.ref(); + Q_ASSERT(fontEngine != oldFontEngine); + oldFontEngine->ref.deref(); + if (oldFontEngine->cache_count == 0 && oldFontEngine->ref == 0) + delete oldFontEngine; +} + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qrawfont_p.h b/src/gui/text/qrawfont_p.h new file mode 100644 index 0000000..f9a9ab5 --- /dev/null +++ b/src/gui/text/qrawfont_p.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRAWFONTPRIVATE_P_H +#define QRAWFONTPRIVATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qrawfont.h" +#include "qfontengine_p.h" +#include + +#if !defined(QT_NO_RAWFONT) + +QT_BEGIN_NAMESPACE + +namespace { class CustomFontFileLoader; } +class Q_AUTOTEST_EXPORT QRawFontPrivate +{ +public: + QRawFontPrivate() + : fontEngine(0) + , hintingPreference(QFont::PreferDefaultHinting) + , thread(0) +#if defined(Q_WS_WIN) + , fontHandle(NULL) + , ptrAddFontMemResourceEx(NULL) + , ptrRemoveFontMemResourceEx(NULL) +#endif + {} + + QRawFontPrivate(const QRawFontPrivate &other) + : hintingPreference(other.hintingPreference) + , thread(other.thread) +#if defined(Q_WS_WIN) + , fontHandle(NULL) + , ptrAddFontMemResourceEx(other.ptrAddFontMemResourceEx) + , ptrRemoveFontMemResourceEx(other.ptrRemoveFontMemResourceEx) + , uniqueFamilyName(other.uniqueFamilyName) +#endif + { + fontEngine = other.fontEngine; + if (fontEngine != 0) + fontEngine->ref.ref(); + } + + ~QRawFontPrivate() + { + Q_ASSERT(ref == 0); + cleanUp(); + } + + void cleanUp(); + void platformCleanUp(); + void platformLoadFromData(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference); + void platformSetPixelSize(int pixelSize); + + static QRawFontPrivate *get(const QRawFont &font) { return font.d.data(); } + + QFontEngine *fontEngine; + QFont::HintingPreference hintingPreference; + QThread *thread; + QAtomicInt ref; + +#if defined(Q_WS_WIN) + HANDLE fontHandle; + + typedef HANDLE (WINAPI *PtrAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *); + typedef BOOL (WINAPI *PtrRemoveFontMemResourceEx)(HANDLE); + + PtrAddFontMemResourceEx ptrAddFontMemResourceEx; + PtrRemoveFontMemResourceEx ptrRemoveFontMemResourceEx; + + QString uniqueFamilyName; + +#endif // Q_WS_WIN +}; + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT + +#endif // QRAWFONTPRIVATE_P_H diff --git a/src/gui/text/qrawfont_win.cpp b/src/gui/text/qrawfont_win.cpp new file mode 100644 index 0000000..fb5c6f4 --- /dev/null +++ b/src/gui/text/qrawfont_win.cpp @@ -0,0 +1,750 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qrawfont_p.h" +#include + +#if !defined(QT_NO_DIRECTWRITE) +# include "qfontenginedirectwrite_p.h" +# include +#endif + +#if !defined(QT_NO_RAWFONT) + +QT_BEGIN_NAMESPACE + +namespace { + + template + struct BigEndian + { + quint8 data[sizeof(T)]; + + operator T() const + { + T littleEndian = 0; + for (int i=0; i &operator=(const T &t) + { + for (int i=0; i> (sizeof(T) - i - 1) * 8) & 0xff); + } + + return *this; + } + }; + +# pragma pack(1) + + // Common structure for all formats of the "name" table + struct NameTable + { + BigEndian format; + BigEndian count; + BigEndian stringOffset; + }; + + struct NameRecord + { + BigEndian platformID; + BigEndian encodingID; + BigEndian languageID; + BigEndian nameID; + BigEndian length; + BigEndian offset; + }; + + struct OffsetSubTable + { + BigEndian scalerType; + BigEndian numTables; + BigEndian searchRange; + BigEndian entrySelector; + BigEndian rangeShift; + }; + + struct TableDirectory + { + BigEndian identifier; + BigEndian checkSum; + BigEndian offset; + BigEndian length; + }; + + struct OS2Table + { + BigEndian version; + BigEndian avgCharWidth; + BigEndian weightClass; + BigEndian widthClass; + BigEndian type; + BigEndian subscriptXSize; + BigEndian subscriptYSize; + BigEndian subscriptXOffset; + BigEndian subscriptYOffset; + BigEndian superscriptXSize; + BigEndian superscriptYSize; + BigEndian superscriptXOffset; + BigEndian superscriptYOffset; + BigEndian strikeOutSize; + BigEndian strikeOutPosition; + BigEndian familyClass; + quint8 panose[10]; + BigEndian unicodeRanges[4]; + quint8 vendorID[4]; + BigEndian selection; + BigEndian firstCharIndex; + BigEndian lastCharIndex; + BigEndian typoAscender; + BigEndian typoDescender; + BigEndian typoLineGap; + BigEndian winAscent; + BigEndian winDescent; + BigEndian codepageRanges[2]; + BigEndian height; + BigEndian capHeight; + BigEndian defaultChar; + BigEndian breakChar; + BigEndian maxContext; + }; + +# pragma pack() + + class EmbeddedFont + { + public: + EmbeddedFont(const QByteArray &fontData); + + QString changeFamilyName(const QString &newFamilyName); + QByteArray data() const { return m_fontData; } + TableDirectory *tableDirectoryEntry(const QByteArray &tagName); + QString familyName(TableDirectory *nameTableDirectory = 0); + + private: + QByteArray m_fontData; + }; + + EmbeddedFont::EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData) + { + } + + TableDirectory *EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName) + { + Q_ASSERT(tagName.size() == 4); + + const BigEndian *tagIdPtr = + reinterpret_cast *>(tagName.constData()); + quint32 tagId = *tagIdPtr; + + OffsetSubTable *offsetSubTable = reinterpret_cast(m_fontData.data()); + TableDirectory *tableDirectory = reinterpret_cast(offsetSubTable + 1); + + TableDirectory *nameTableDirectoryEntry = 0; + for (int i=0; inumTables; ++i, ++tableDirectory) { + if (tableDirectory->identifier == tagId) { + nameTableDirectoryEntry = tableDirectory; + break; + } + } + + return nameTableDirectoryEntry; + } + + QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry) + { + QString name; + + if (nameTableDirectoryEntry == 0) + nameTableDirectoryEntry = tableDirectoryEntry("name"); + + if (nameTableDirectoryEntry != 0) { + NameTable *nameTable = reinterpret_cast(m_fontData.data() + + nameTableDirectoryEntry->offset); + NameRecord *nameRecord = reinterpret_cast(nameTable + 1); + for (int i=0; icount; ++i, ++nameRecord) { + if (nameRecord->nameID == 1 + && nameRecord->platformID == 3 // Windows + && nameRecord->languageID == 0x0409) { // US English + const void *ptr = reinterpret_cast(nameTable) + + nameTable->stringOffset + + nameRecord->offset; + + const BigEndian *s = reinterpret_cast *>(ptr); + for (int j=0; jlength / sizeof(quint16); ++j) + name += QChar(s[j]); + + break; + } + } + } + + return name; + } + + QString EmbeddedFont::changeFamilyName(const QString &newFamilyName) + { + TableDirectory *nameTableDirectoryEntry = tableDirectoryEntry("name"); + if (nameTableDirectoryEntry == 0) + return QString(); + + QString oldFamilyName = familyName(nameTableDirectoryEntry); + + // Reserve size for name table header, five required name records and string + const int requiredRecordCount = 5; + quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 }; + + int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount; + int newFamilyNameSize = newFamilyName.size() * sizeof(quint16); + + const QString regularString = QString::fromLatin1("Regular"); + int regularStringSize = regularString.size() * sizeof(quint16); + + // Align table size of table to 32 bits (pad with 0) + int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4; + + QByteArray newNameTable(fullSize, char(0)); + + { + NameTable *nameTable = reinterpret_cast(newNameTable.data()); + nameTable->count = requiredRecordCount; + nameTable->stringOffset = sizeOfHeader; + + NameRecord *nameRecord = reinterpret_cast(nameTable + 1); + for (int i=0; inameID = nameIds[i]; + nameRecord->encodingID = 1; + nameRecord->languageID = 0x0409; + nameRecord->platformID = 3; + nameRecord->length = newFamilyNameSize; + + // Special case for sub-family + if (nameIds[i] == 4) { + nameRecord->offset = newFamilyNameSize; + nameRecord->length = regularStringSize; + } + } + + // nameRecord now points to string data + BigEndian *stringStorage = reinterpret_cast *>(nameRecord); + const quint16 *sourceString = newFamilyName.utf16(); + for (int i=0; i(newNameTable.data()); + quint32 *tableEnd = reinterpret_cast(newNameTable.data() + fullSize); + + quint32 checkSum = 0; + while (p < tableEnd) + checkSum += *(p++); + + nameTableDirectoryEntry->checkSum = checkSum; + nameTableDirectoryEntry->offset = m_fontData.size(); + nameTableDirectoryEntry->length = fullSize; + + m_fontData.append(newNameTable); + + return oldFamilyName; + } + +#if !defined(QT_NO_DIRECTWRITE) + + class DirectWriteFontFileStream: public IDWriteFontFileStream + { + public: + DirectWriteFontFileStream(const QByteArray &fontData) + : m_fontData(fontData) + , m_referenceCount(0) + { + } + + ~DirectWriteFontFileStream() + { + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset, + UINT64 fragmentSize, OUT void **fragmentContext); + void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext); + HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize); + HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime); + + private: + QByteArray m_fontData; + ULONG m_referenceCount; + }; + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object) + { + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { + *object = this; + AddRef(); + return S_OK; + } else { + *object = NULL; + return E_NOINTERFACE; + } + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef() + { + return InterlockedIncrement(&m_referenceCount); + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release() + { + ULONG newCount = InterlockedDecrement(&m_referenceCount); + if (newCount == 0) + delete this; + return newCount; + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment( + const void **fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + OUT void **fragmentContext) + { + *fragmentContext = NULL; + if (fragmentSize + fileOffset <= m_fontData.size()) { + *fragmentStart = m_fontData.data() + fileOffset; + return S_OK; + } else { + *fragmentStart = NULL; + return E_FAIL; + } + } + + void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *) + { + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize) + { + *fileSize = m_fontData.size(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime) + { + *lastWriteTime = 0; + return E_NOTIMPL; + } + + class DirectWriteFontFileLoader: public IDWriteFontFileLoader + { + public: + DirectWriteFontFileLoader() : m_referenceCount(0) {} + + ~DirectWriteFontFileLoader() + { + } + + inline void addKey(const void *key, const QByteArray &fontData) + { + Q_ASSERT(!m_fontDatas.contains(key)); + m_fontDatas.insert(key, fontData); + } + + inline void removeKey(const void *key) + { + m_fontDatas.remove(key); + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + OUT IDWriteFontFileStream **fontFileStream); + + private: + ULONG m_referenceCount; + QHash m_fontDatas; + }; + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid, + void **object) + { + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) { + *object = this; + AddRef(); + return S_OK; + } else { + *object = NULL; + return E_NOINTERFACE; + } + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef() + { + return InterlockedIncrement(&m_referenceCount); + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release() + { + ULONG newCount = InterlockedDecrement(&m_referenceCount); + if (newCount == 0) + delete this; + return newCount; + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey( + void const *fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + IDWriteFontFileStream **fontFileStream) + { + Q_UNUSED(fontFileReferenceKeySize); + + if (fontFileReferenceKeySize != sizeof(const void *)) { + qWarning("DirectWriteFontFileLoader::CreateStreamFromKey: Wrong key size"); + return E_FAIL; + } + + const void *key = *reinterpret_cast(fontFileReferenceKey); + *fontFileStream = NULL; + if (!m_fontDatas.contains(key)) + return E_FAIL; + + QByteArray fontData = m_fontDatas.value(key); + DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData); + stream->AddRef(); + *fontFileStream = stream; + + return S_OK; + } + + class CustomFontFileLoader + { + public: + CustomFontFileLoader() : m_directWriteFactory(0), m_directWriteFontFileLoader(0) + { + HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(&m_directWriteFactory)); + if (FAILED(hres)) { + qErrnoWarning(hres, "CustomFontFileLoader::CustomFontFileLoader: " + "DWriteCreateFactory failed."); + } else { + m_directWriteFontFileLoader = new DirectWriteFontFileLoader(); + m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader); + } + } + + ~CustomFontFileLoader() + { + if (m_directWriteFactory != 0 && m_directWriteFontFileLoader != 0) + m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader); + + if (m_directWriteFactory != 0) + m_directWriteFactory->Release(); + } + + void addKey(const void *key, const QByteArray &fontData) + { + if (m_directWriteFontFileLoader != 0) + m_directWriteFontFileLoader->addKey(key, fontData); + } + + void removeKey(const void *key) + { + if (m_directWriteFontFileLoader != 0) + m_directWriteFontFileLoader->removeKey(key); + } + + IDWriteFontFileLoader *loader() const + { + return m_directWriteFontFileLoader; + } + + private: + IDWriteFactory *m_directWriteFactory; + DirectWriteFontFileLoader *m_directWriteFontFileLoader; + }; + +#endif + +} // Anonymous namespace + + +// From qfontdatabase_win.cpp +extern QFontEngine *qt_load_font_engine_win(const QFontDef &request); +// From qfontdatabase.cpp +extern QFont::Weight weightFromInteger(int weight); + +void QRawFontPrivate::platformCleanUp() +{ + if (fontHandle != NULL) { + if (ptrRemoveFontMemResourceEx == NULL) { + void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); + ptrRemoveFontMemResourceEx = + reinterpret_cast(func); + } + + if (ptrRemoveFontMemResourceEx == NULL) { + qWarning("QRawFont::platformCleanUp: Can't find RemoveFontMemResourceEx in gdi32"); + fontHandle = NULL; + } else { + ptrRemoveFontMemResourceEx(fontHandle); + fontHandle = NULL; + } + } +} + +void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData, + int pixelSize, + QFont::HintingPreference hintingPreference) +{ + QByteArray fontData(_fontData); + EmbeddedFont font(fontData); + +#if !defined(QT_NO_DIRECTWRITE) + if (hintingPreference == QFont::PreferDefaultHinting + || hintingPreference == QFont::PreferFullHinting) +#endif + { + GUID guid; + CoCreateGuid(&guid); + + uniqueFamilyName = QString::fromLatin1("f") + + QString::number(guid.Data1, 36) + QLatin1Char('-') + + QString::number(guid.Data2, 36) + QLatin1Char('-') + + QString::number(guid.Data3, 36) + QLatin1Char('-') + + QString::number(*reinterpret_cast(guid.Data4), 36); + + QString actualFontName = font.changeFamilyName(uniqueFamilyName); + if (actualFontName.isEmpty()) { + qWarning("QRawFont::platformLoadFromData: Can't change family name of font"); + return; + } + + if (ptrAddFontMemResourceEx == NULL || ptrRemoveFontMemResourceEx == NULL) { + void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); + ptrRemoveFontMemResourceEx = + reinterpret_cast(func); + + func = QSystemLibrary::resolve(QLatin1String("gdi32"), "AddFontMemResourceEx"); + ptrAddFontMemResourceEx = + reinterpret_cast(func); + } + + Q_ASSERT(fontHandle == NULL); + if (ptrAddFontMemResourceEx != NULL && ptrRemoveFontMemResourceEx != NULL) { + DWORD count = 0; + fontData = font.data(); + fontHandle = ptrAddFontMemResourceEx(fontData.data(), fontData.size(), 0, &count); + + if (count == 0 && fontHandle != NULL) { + ptrRemoveFontMemResourceEx(fontHandle); + fontHandle = NULL; + } + } + + if (fontHandle == NULL) { + qWarning("QRawFont::platformLoadFromData: AddFontMemResourceEx failed"); + } else { + QFontDef request; + request.family = uniqueFamilyName; + request.pixelSize = pixelSize; + request.styleStrategy = QFont::NoFontMerging | QFont::PreferMatch; + request.hintingPreference = hintingPreference; + + fontEngine = qt_load_font_engine_win(request); + if (request.family != fontEngine->fontDef.family) { + qWarning("QRawFont::platformLoadFromData: Failed to load font. " + "Got fallback instead: %s", qPrintable(fontEngine->fontDef.family)); + if (fontEngine->cache_count == 0 && fontEngine->ref == 0) + delete fontEngine; + fontEngine = 0; + } else { + Q_ASSERT(fontEngine->cache_count == 0 && fontEngine->ref == 0); + + // Override the generated font name + fontEngine->fontDef.family = actualFontName; + fontEngine->ref.ref(); + } + } + } +#if !defined(QT_NO_DIRECTWRITE) + else { + CustomFontFileLoader fontFileLoader; + fontFileLoader.addKey(this, fontData); + + IDWriteFactory *factory = NULL; + HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(&factory)); + if (FAILED(hres)) { + qErrnoWarning(hres, "QRawFont::platformLoadFromData: DWriteCreateFactory failed"); + return; + } + + IDWriteFontFile *fontFile = NULL; + void *key = this; + + hres = factory->CreateCustomFontFileReference(&key, sizeof(void *), + fontFileLoader.loader(), &fontFile); + if (FAILED(hres)) { + qErrnoWarning(hres, "QRawFont::platformLoadFromData: " + "CreateCustomFontFileReference failed"); + factory->Release(); + return; + } + + BOOL isSupportedFontType; + DWRITE_FONT_FILE_TYPE fontFileType; + DWRITE_FONT_FACE_TYPE fontFaceType; + UINT32 numberOfFaces; + fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces); + if (!isSupportedFontType) { + fontFile->Release(); + factory->Release(); + return; + } + + IDWriteFontFace *directWriteFontFace = NULL; + hres = factory->CreateFontFace(fontFaceType, 1, &fontFile, 0, DWRITE_FONT_SIMULATIONS_NONE, + &directWriteFontFace); + if (FAILED(hres)) { + qErrnoWarning(hres, "QRawFont::platformLoadFromData: CreateFontFace failed"); + fontFile->Release(); + factory->Release(); + return; + } + + fontFile->Release(); + + fontEngine = new QFontEngineDirectWrite(factory, directWriteFontFace, pixelSize); + + // Get font family from font data + fontEngine->fontDef.family = font.familyName(); + fontEngine->ref.ref(); + + directWriteFontFace->Release(); + factory->Release(); + } +#endif + + // Get style and weight info + if (fontEngine != 0) { + TableDirectory *os2TableEntry = font.tableDirectoryEntry("OS/2"); + if (os2TableEntry != 0) { + const OS2Table *os2Table = + reinterpret_cast(fontData.constData() + + os2TableEntry->offset); + + bool italic = os2Table->selection & 1; + bool oblique = os2Table->selection & 128; + + if (italic) + fontEngine->fontDef.style = QFont::StyleItalic; + else if (oblique) + fontEngine->fontDef.style = QFont::StyleOblique; + else + fontEngine->fontDef.style = QFont::StyleNormal; + + fontEngine->fontDef.weight = weightFromInteger(os2Table->weightClass); + } + } +} + +void QRawFontPrivate::platformSetPixelSize(int pixelSize) +{ + if (fontEngine == NULL) + return; + + QFontEngine *oldFontEngine = fontEngine; + +#if !defined(QT_NO_DIRECTWRITE) + if (fontEngine->type() == QFontEngine::Win) +#endif + + { + QFontDef request = fontEngine->fontDef; + QString actualFontName = request.family; + if (!uniqueFamilyName.isEmpty()) + request.family = uniqueFamilyName; + request.pixelSize = pixelSize; + + fontEngine = qt_load_font_engine_win(request); + if (fontEngine != NULL) { + fontEngine->fontDef.family = actualFontName; + fontEngine->ref.ref(); + } + } + +#if !defined(QT_NO_DIRECTWRITE) + else { + QFontEngineDirectWrite *dWriteFE = static_cast(fontEngine); + fontEngine = new QFontEngineDirectWrite(dWriteFE->m_directWriteFactory, + dWriteFE->m_directWriteFontFace, + pixelSize); + + fontEngine->fontDef = dWriteFE->fontDef; + fontEngine->fontDef.pixelSize = pixelSize; + fontEngine->ref.ref(); + } +#endif + + Q_ASSERT(fontEngine != oldFontEngine); + oldFontEngine->ref.deref(); + if (oldFontEngine->cache_count == 0 && oldFontEngine->ref == 0) + delete oldFontEngine; +} + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index afe6949..93f71d3 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -54,12 +54,18 @@ #include "qpainterpath.h" #include "qglyphs.h" #include "qglyphs_p.h" +#include "qrawfont.h" +#include "qrawfont_p.h" #include #include #include "qfontengine_p.h" +#if !defined(QT_NO_FREETYPE) +# include "qfontengine_ft_p.h" +#endif + QT_BEGIN_NAMESPACE #define ObjectSelectionBrush (QTextFormat::ForegroundBrush + 1) @@ -1158,6 +1164,7 @@ static inline QRectF clipIfValid(const QRectF &rect, const QRectF &clip) \sa draw(), QPainter::drawGlyphs() */ +#if !defined(QT_NO_RAWFONT) QList QTextLayout::glyphs() const { QList glyphs; @@ -1166,6 +1173,7 @@ QList QTextLayout::glyphs() const return glyphs; } +#endif // QT_NO_RAWFONT /*! Draws the whole layout on the painter \a p at the position specified by \a pos. @@ -2257,6 +2265,7 @@ namespace { \sa QTextLayout::glyphs() */ +#if !defined(QT_NO_RAWFONT) QList QTextLine::glyphs(int from, int length) const { const QScriptLine &line = eng->lines[i]; @@ -2331,7 +2340,35 @@ QList QTextLine::glyphs(int from, int length) const QFontEngine *fontEngine = keys.at(i); // Make a font for this particular engine - QFont font = fontEngine->createExplicitFont(); + QRawFont font; + QRawFontPrivate *fontD = QRawFontPrivate::get(font); + fontD->fontEngine = fontEngine; + fontD->fontEngine->ref.ref(); + +#if defined(Q_WS_WIN) + if (fontEngine->supportsSubPixelPositions()) + fontD->hintingPreference = QFont::PreferVerticalHinting; + else + fontD->hintingPreference = QFont::PreferFullHinting; +#elif defined(Q_WS_MAC) + fontD->hintingPreference = QFont::PreferNoHinting; +#elif !defined(QT_NO_FREETYPE) + if (fontEngine->type() == QFontEngine::Freetype) { + QFontEngineFT *freeTypeEngine = static_cast(fontEngine); + switch (freeTypeEngine->defaultHintStyle()) { + case QFontEngineFT::HintNone: + fontD->hintingPreference = QFont::PreferNoHinting; + break; + case QFontEngineFT::HintLight: + fontD->hintingPreference = QFont::PreferVerticalHinting; + break; + case QFontEngineFT::HintMedium: + case QFontEngineFT::HintFull: + fontD->hintingPreference = QFont::PreferFullHinting; + break; + }; + } +#endif QList glyphLayouts = glyphLayoutHash.values(fontEngine); for (int j=0; j QTextLine::glyphs(int from, int length) const const QGlyphLayout &glyphLayout = glyphLayouts.at(j).glyphLayout; const QTextItem::RenderFlags &flags = glyphLayouts.at(j).flags; - font.setOverline(flags.testFlag(QTextItem::Overline)); - font.setUnderline(flags.testFlag(QTextItem::Underline)); - font.setStrikeOut(flags.testFlag(QTextItem::StrikeOut)); - QVarLengthArray glyphsArray; QVarLengthArray positionsArray; @@ -2361,19 +2394,22 @@ QList QTextLine::glyphs(int from, int length) const glyphIndexes.setGlyphIndexes(glyphs); glyphIndexes.setPositions(positions); - QPair key(fontEngine, int(flags)); + glyphIndexes.setOverline(flags.testFlag(QTextItem::Overline)); + glyphIndexes.setUnderline(flags.testFlag(QTextItem::Underline)); + glyphIndexes.setStrikeOut(flags.testFlag(QTextItem::StrikeOut)); + glyphIndexes.setFont(font); + QPair key(fontEngine, int(flags)); if (!glyphsHash.contains(key)) - glyphsHash.insert(key, QGlyphs()); - - QGlyphs &target = glyphsHash[key]; - target += glyphIndexes; - target.setFont(font); + glyphsHash.insert(key, glyphIndexes); + else + glyphsHash[key] += glyphIndexes; } } return glyphsHash.values(); } +#endif // QT_NO_RAWFONT /*! \fn void QTextLine::draw(QPainter *painter, const QPointF &position, const QTextLayout::FormatRange *selection) const diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h index 0f64c33..9dd8ebd 100644 --- a/src/gui/text/qtextlayout.h +++ b/src/gui/text/qtextlayout.h @@ -167,7 +167,9 @@ public: qreal minimumWidth() const; qreal maximumWidth() const; +#if !defined(QT_NO_RAWFONT) QList glyphs() const; +#endif QTextEngine *engine() const { return d; } void setFlags(int flags); @@ -239,7 +241,10 @@ public: private: QTextLine(int line, QTextEngine *e) : i(line), eng(e) {} void layout_helper(int numGlyphs); + +#if !defined(QT_NO_RAWFONT) QList glyphs(int from, int length) const; +#endif friend class QTextLayout; friend class QTextFragment; diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index 0081550..0a9dff8 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -1661,6 +1661,7 @@ QTextBlock::iterator &QTextBlock::iterator::operator--() \sa QGlyphs, QTextBlock::layout(), QTextLayout::position(), QPainter::drawGlyphs() */ +#if !defined(QT_NO_RAWFONT) QList QTextFragment::glyphs() const { if (!p || !n) @@ -1684,6 +1685,7 @@ QList QTextFragment::glyphs() const return ret; } +#endif // QT_NO_RAWFONT /*! Returns the position of this text fragment in the document. diff --git a/src/gui/text/qtextobject.h b/src/gui/text/qtextobject.h index fface3f..2e588c2 100644 --- a/src/gui/text/qtextobject.h +++ b/src/gui/text/qtextobject.h @@ -316,7 +316,9 @@ public: int charFormatIndex() const; QString text() const; +#if !defined(QT_NO_RAWFONT) QList glyphs() const; +#endif private: const QTextDocumentPrivate *p; diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index 7fb2783..df9398c 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -41,7 +41,9 @@ HEADERS += \ text/qstatictext_p.h \ text/qstatictext.h \ text/qglyphs.h \ - text/qglyphs_p.h + text/qglyphs_p.h \ + text/qrawfont.h \ + text/qrawfont_p.h SOURCES += \ text/qfont.cpp \ @@ -72,12 +74,14 @@ SOURCES += \ text/qzip.cpp \ text/qtextodfwriter.cpp \ text/qstatictext.cpp \ - text/qglyphs.cpp + text/qglyphs.cpp \ + text/qrawfont.cpp win32 { SOURCES += \ text/qfont_win.cpp \ - text/qfontengine_win.cpp + text/qfontengine_win.cpp \ + text/qrawfont_win.cpp HEADERS += text/qfontengine_win_p.h } @@ -95,7 +99,8 @@ unix:x11 { SOURCES += \ text/qfont_x11.cpp \ text/qfontengine_x11.cpp \ - text/qfontengine_ft.cpp + text/qfontengine_ft.cpp \ + text/qrawfont_ft.cpp } !embedded:!qpa:!x11:mac { @@ -104,7 +109,8 @@ unix:x11 { OBJECTIVE_HEADERS += \ text/qfontengine_coretext_p.h SOURCES += \ - text/qfont_mac.cpp + text/qfont_mac.cpp \ + text/qrawfont_mac.cpp OBJECTIVE_SOURCES += \ text/qfontengine_coretext.mm \ text/qfontengine_mac.mm @@ -116,7 +122,8 @@ embedded { text/qfontengine_qws.cpp \ text/qfontengine_ft.cpp \ text/qfontengine_qpf.cpp \ - text/qabstractfontengine_qws.cpp + text/qabstractfontengine_qws.cpp \ + text/qrawfont_ft.cpp HEADERS += \ text/qfontengine_ft_p.h \ text/qfontengine_qpf_p.h \ @@ -143,7 +150,8 @@ symbian { text/qfont_s60.cpp contains(QT_CONFIG, freetype) { SOURCES += \ - text/qfontengine_ft.cpp + text/qfontengine_ft.cpp \ + text/qrawfont_ft.cpp HEADERS += \ text/qfontengine_ft_p.h DEFINES += \ diff --git a/tests/auto/gui.pro b/tests/auto/gui.pro index 186f00c..6230220 100644 --- a/tests/auto/gui.pro +++ b/tests/auto/gui.pro @@ -139,6 +139,7 @@ SUBDIRS=\ qpushbutton \ qquaternion \ qradiobutton \ + qrawfont \ qregexpvalidator \ qregion \ qscrollarea \ diff --git a/tests/auto/qglyphs/tst_qglyphs.cpp b/tests/auto/qglyphs/tst_qglyphs.cpp index 1c0aa9e..a9ae556 100644 --- a/tests/auto/qglyphs/tst_qglyphs.cpp +++ b/tests/auto/qglyphs/tst_qglyphs.cpp @@ -46,6 +46,8 @@ #include #include +#if !defined(QT_NO_RAWFONT) + // #define DEBUG_SAVE_IMAGE class tst_QGlyphs: public QObject @@ -116,7 +118,7 @@ static QGlyphs make_dummy_indexes() positions.append(QPointF(3, 4)); positions.append(QPointF(5, 6)); - glyphs.setFont(font); + glyphs.setFont(QRawFont::fromFont(font)); glyphs.setGlyphIndexes(glyphIndexes); glyphs.setPositions(positions); @@ -141,7 +143,7 @@ void tst_QGlyphs::copyConstructor() positions.append(QPointF(3, 4)); positions.append(QPointF(5, 6)); - glyphs.setFont(font); + glyphs.setFont(QRawFont::fromFont(font)); glyphs.setGlyphIndexes(glyphIndexes); glyphs.setPositions(positions); } @@ -180,14 +182,16 @@ void tst_QGlyphs::equalsOperator_data() positions[2] += QPointF(1, 1); busted.setPositions(positions); + QTest::newRow("Different positions") << one << busted << false; } { QGlyphs busted(two); - QFont font = busted.font(); - font.setPointSize(font.pointSize() * 2); - busted.setFont(font); + + QFont font; + font.setPixelSize(busted.font().pixelSize() * 2); + busted.setFont(QRawFont::fromFont(font)); QTest::newRow("Different fonts") << one << busted << false; } @@ -288,7 +292,7 @@ void tst_QGlyphs::drawNonExistentGlyphs() QGlyphs glyphs; glyphs.setGlyphIndexes(glyphIndexes); glyphs.setPositions(glyphPositions); - glyphs.setFont(m_testFont); + glyphs.setFont(QRawFont::fromFont(m_testFont)); QPixmap image(1000, 1000); image.fill(Qt::white); @@ -571,3 +575,4 @@ void tst_QGlyphs::drawRightToLeft() QTEST_MAIN(tst_QGlyphs) #include "tst_qglyphs.moc" +#endif // QT_NO_RAWFONT diff --git a/tests/auto/qrawfont/qrawfont.pro b/tests/auto/qrawfont/qrawfont.pro new file mode 100644 index 0000000..ccdccfb --- /dev/null +++ b/tests/auto/qrawfont/qrawfont.pro @@ -0,0 +1,13 @@ +load(qttest_p4) +QT = core gui + +SOURCES += \ + tst_qrawfont.cpp + +INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src + +wince*|symbian*: { + DEFINES += SRCDIR=\\\"\\\" +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} diff --git a/tests/auto/qrawfont/testfont.ttf b/tests/auto/qrawfont/testfont.ttf new file mode 100644 index 0000000..d6042d2 Binary files /dev/null and b/tests/auto/qrawfont/testfont.ttf differ diff --git a/tests/auto/qrawfont/testfont_bold_italic.ttf b/tests/auto/qrawfont/testfont_bold_italic.ttf new file mode 100644 index 0000000..9f65ac8 Binary files /dev/null and b/tests/auto/qrawfont/testfont_bold_italic.ttf differ diff --git a/tests/auto/qrawfont/tst_qrawfont.cpp b/tests/auto/qrawfont/tst_qrawfont.cpp new file mode 100644 index 0000000..c20b41d --- /dev/null +++ b/tests/auto/qrawfont/tst_qrawfont.cpp @@ -0,0 +1,812 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include + +#if !defined(QT_NO_RAWFONT) + +class tst_QRawFont: public QObject +{ + Q_OBJECT + +private slots: + void invalidRawFont(); + + void explicitRawFontNotLoadedInDatabase_data(); + void explicitRawFontNotLoadedInDatabase(); + + void explicitRawFontNotAvailableInSystem_data(); + void explicitRawFontNotAvailableInSystem(); + + void correctFontData_data(); + void correctFontData(); + + void glyphIndices(); + + void advances_data(); + void advances(); + + void textLayout(); + + void fontTable_data(); + void fontTable(); + + void supportedWritingSystems_data(); + void supportedWritingSystems(); + + void supportsCharacter_data(); + void supportsCharacter(); + + void supportsUcs4Character_data(); + void supportsUcs4Character(); + + void fromFont_data(); + void fromFont(); + + void copyConstructor_data(); + void copyConstructor(); + + void detach_data(); + void detach(); + + void unsupportedWritingSystem_data(); + void unsupportedWritingSystem(); +}; + +Q_DECLARE_METATYPE(QFont::HintingPreference) +Q_DECLARE_METATYPE(QFont::Style) +Q_DECLARE_METATYPE(QFont::Weight) +Q_DECLARE_METATYPE(QFontDatabase::WritingSystem) + +void tst_QRawFont::invalidRawFont() +{ + QRawFont font; + QVERIFY(!font.isValid()); + QCOMPARE(font.pixelSize(), -1); + QVERIFY(font.familyName().isEmpty()); + QCOMPARE(font.style(), QFont::StyleNormal); + QCOMPARE(font.weight(), -1); + QCOMPARE(font.ascent(), 0.0); + QCOMPARE(font.descent(), 0.0); + QVERIFY(font.glyphIndexesForString(QLatin1String("Test")).isEmpty()); +} + +void tst_QRawFont::explicitRawFontNotLoadedInDatabase_data() +{ + QTest::addColumn("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting") << QFont::PreferFullHinting; +} + +void tst_QRawFont::explicitRawFontNotLoadedInDatabase() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QRawFont font(QLatin1String(SRCDIR "testfont.ttf"), 10, hintingPreference); + QVERIFY(font.isValid()); + + QVERIFY(!QFontDatabase().families().contains(font.familyName())); +} + +void tst_QRawFont::explicitRawFontNotAvailableInSystem_data() +{ + QTest::addColumn("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting") << QFont::PreferFullHinting; +} + +void tst_QRawFont::explicitRawFontNotAvailableInSystem() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QRawFont rawfont(QLatin1String(SRCDIR "testfont.ttf"), 10, hintingPreference); + + { + QFont font(rawfont.familyName(), 10); + + QVERIFY(!font.exactMatch()); + QVERIFY(font.family() != QFontInfo(font).family()); + } +} + +void tst_QRawFont::correctFontData_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("expectedFamilyName"); + QTest::addColumn("style"); + QTest::addColumn("weight"); + QTest::addColumn("hintingPreference"); + QTest::addColumn("unitsPerEm"); + QTest::addColumn("pixelSize"); + + int hintingPreferences[] = { + int(QFont::PreferDefaultHinting), + int(QFont::PreferNoHinting), + int(QFont::PreferVerticalHinting), + int(QFont::PreferFullHinting), + -1 + }; + int *hintingPreference = hintingPreferences; + + while (*hintingPreference >= 0) { + QString fileName = QLatin1String(SRCDIR "testfont.ttf"); + QString title = fileName + + QLatin1String(": hintingPreference=") + + QString::number(*hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QString::fromLatin1("QtBidiTestFont") + << QFont::StyleNormal + << QFont::Normal + << QFont::HintingPreference(*hintingPreference) + << 1000.0 + << 10; + + fileName = QLatin1String(SRCDIR "testfont_bold_italic.ttf"); + title = fileName + + QLatin1String(": hintingPreference=") + + QString::number(*hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QString::fromLatin1("QtBidiTestFont") + << QFont::StyleItalic + << QFont::Bold + << QFont::HintingPreference(*hintingPreference) + << 1000.0 + << 10; + + ++hintingPreference; + } +} + +void tst_QRawFont::correctFontData() +{ + QFETCH(QString, fileName); + QFETCH(QString, expectedFamilyName); + QFETCH(QFont::Style, style); + QFETCH(QFont::Weight, weight); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(qreal, unitsPerEm); + QFETCH(int, pixelSize); + + QRawFont font(fileName, 10, hintingPreference); + QVERIFY(font.isValid()); + + QCOMPARE(font.familyName(), expectedFamilyName); + QCOMPARE(font.style(), style); + QCOMPARE(font.weight(), int(weight)); + QCOMPARE(font.hintingPreference(), hintingPreference); + QCOMPARE(font.unitsPerEm(), unitsPerEm); + QCOMPARE(font.pixelSize(), pixelSize); +} + +void tst_QRawFont::glyphIndices() +{ + QRawFont font(QLatin1String(SRCDIR "testfont.ttf"), 10); + QVERIFY(font.isValid()); + + QVector glyphIndices = font.glyphIndexesForString(QLatin1String("Foobar")); + QVector expectedGlyphIndices; + expectedGlyphIndices << 44 << 83 << 83 << 70 << 69 << 86; + + QCOMPARE(glyphIndices, expectedGlyphIndices); +} + +void tst_QRawFont::advances_data() +{ + QTest::addColumn("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting") << QFont::PreferFullHinting; +} + +void tst_QRawFont::advances() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QRawFont font(QLatin1String(SRCDIR "testfont.ttf"), 10, hintingPreference); + QVERIFY(font.isValid()); + + QRawFontPrivate *font_d = QRawFontPrivate::get(font); + QVERIFY(font_d->fontEngine != 0); + + QVector glyphIndices; + glyphIndices << 44 << 83 << 83 << 70 << 69 << 86; // "Foobar" + + bool supportsSubPixelPositions = font_d->fontEngine->supportsSubPixelPositions(); + QVector advances = font.advancesForGlyphIndexes(glyphIndices); + for (int i=0; i 8.0); + + QVERIFY(qFuzzyIsNull(advances.at(i).y())); + } +} + +void tst_QRawFont::textLayout() +{ + QFontDatabase fontDatabase; + int id = fontDatabase.addApplicationFont(SRCDIR "testfont.ttf"); + QVERIFY(id >= 0); + + QString familyName = QString::fromLatin1("QtBidiTestFont"); + QFont font(familyName); + font.setPixelSize(18); + QCOMPARE(QFontInfo(font).family(), familyName); + + QTextLayout layout(QLatin1String("Foobar")); + layout.setFont(font); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList glyphss = layout.glyphs(); + QCOMPARE(glyphss.size(), 1); + + QGlyphs glyphs = glyphss.at(0); + + QRawFont rawFont = glyphs.font(); + QVERIFY(rawFont.isValid()); + QCOMPARE(rawFont.familyName(), familyName); + QCOMPARE(rawFont.pixelSize(), 18); + + QVector expectedGlyphIndices; + expectedGlyphIndices << 44 << 83 << 83 << 70 << 69 << 86; + + QCOMPARE(glyphs.glyphIndexes(), expectedGlyphIndices); + + QVERIFY(fontDatabase.removeApplicationFont(id)); +} + +void tst_QRawFont::fontTable_data() +{ + QTest::addColumn("tagName"); + QTest::addColumn("hintingPreference"); + QTest::addColumn("offset"); + QTest::addColumn("expectedValue"); + + QTest::newRow("Head table, magic number, default hinting") + << QByteArray("head") + << QFont::PreferDefaultHinting + << 12 + << (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? 0x5F0F3CF5 + : 0xF53C0F5F); + + QTest::newRow("Head table, magic number, no hinting") + << QByteArray("head") + << QFont::PreferNoHinting + << 12 + << (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? 0x5F0F3CF5 + : 0xF53C0F5F); + + QTest::newRow("Head table, magic number, vertical hinting") + << QByteArray("head") + << QFont::PreferVerticalHinting + << 12 + << (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? 0x5F0F3CF5 + : 0xF53C0F5F); + + QTest::newRow("Head table, magic number, full hinting") + << QByteArray("head") + << QFont::PreferFullHinting + << 12 + << (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? 0x5F0F3CF5 + : 0xF53C0F5F); +} + +void tst_QRawFont::fontTable() +{ + QFETCH(QByteArray, tagName); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(int, offset); + QFETCH(quint32, expectedValue); + + QRawFont font(QString::fromLatin1(SRCDIR "testfont.ttf"), 10, hintingPreference); + QVERIFY(font.isValid()); + + QByteArray table = font.fontTable(tagName); + QVERIFY(!table.isEmpty()); + + const quint32 *value = reinterpret_cast(table.constData() + offset); + QCOMPARE(*value, expectedValue); +} + +typedef QList WritingSystemList; +Q_DECLARE_METATYPE(WritingSystemList) + +void tst_QRawFont::supportedWritingSystems_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("writingSystems"); + QTest::addColumn("hintingPreference"); + + for (int hintingPreference=QFont::PreferDefaultHinting; + hintingPreference<=QFont::PreferFullHinting; + ++hintingPreference) { + + QTest::newRow(qPrintable(QString::fromLatin1("testfont.ttf, hintingPreference=%1") + .arg(hintingPreference))) + << QString::fromLatin1(SRCDIR "testfont.ttf") + << (QList() + << QFontDatabase::Latin + << QFontDatabase::Hebrew + << QFontDatabase::Vietnamese) // Vietnamese uses same unicode bits as Latin + << QFont::HintingPreference(hintingPreference); + + QTest::newRow(qPrintable(QString::fromLatin1("testfont_bold_italic.ttf, hintingPreference=%1") + .arg(hintingPreference))) + << QString::fromLatin1(SRCDIR "testfont_bold_italic.ttf") + << (QList() + << QFontDatabase::Latin + << QFontDatabase::Hebrew + << QFontDatabase::Devanagari + << QFontDatabase::Vietnamese) // Vietnamese uses same unicode bits as Latin + << QFont::HintingPreference(hintingPreference); + } +} + +void tst_QRawFont::supportedWritingSystems() +{ + QFETCH(QString, fileName); + QFETCH(WritingSystemList, writingSystems); + QFETCH(QFont::HintingPreference, hintingPreference); + + QRawFont font(fileName, 10, hintingPreference); + QVERIFY(font.isValid()); + + WritingSystemList actualWritingSystems = font.supportedWritingSystems(); + QCOMPARE(actualWritingSystems.size(), writingSystems.size()); + + foreach (QFontDatabase::WritingSystem writingSystem, writingSystems) + QVERIFY(actualWritingSystems.contains(writingSystem)); +} + +void tst_QRawFont::supportsCharacter_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("hintingPreference"); + QTest::addColumn("character"); + QTest::addColumn("shouldBeSupported"); + + const char *fileNames[2] = { + SRCDIR "testfont.ttf", + SRCDIR "testfont_bold_italic.ttf" + }; + + for (int hintingPreference=QFont::PreferDefaultHinting; + hintingPreference<=QFont::PreferFullHinting; + ++hintingPreference) { + + for (int i=0; i<2; ++i) { + QString fileName = QLatin1String(fileNames[i]); + + // Latin text + for (char ch='!'; ch<='~'; ++ch) { + QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3") + .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(hintingPreference) + << QChar::fromLatin1(ch) + << true; + } + + // Hebrew text + for (quint16 ch=0x05D0; ch<=0x05EA; ++ch) { + QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3") + .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(hintingPreference) + << QChar(ch) + << true; + } + + QTest::newRow(qPrintable(QString::fromLatin1("Missing character, %1, hintingPreference=%2") + .arg(fileName).arg(hintingPreference))) + << fileName + << QFont::HintingPreference(hintingPreference) + << QChar(0xD8) + << false; + } + } +} + +void tst_QRawFont::supportsCharacter() +{ + QFETCH(QString, fileName); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(QChar, character); + QFETCH(bool, shouldBeSupported); + + QRawFont font(fileName, 10, hintingPreference); + QVERIFY(font.isValid()); + + QCOMPARE(font.supportsCharacter(character), shouldBeSupported); +} + +void tst_QRawFont::supportsUcs4Character_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("hintingPreference"); + QTest::addColumn("ucs4"); + QTest::addColumn("shouldBeSupported"); + + // Gothic text + for (int hintingPreference=QFont::PreferDefaultHinting; + hintingPreference<=QFont::PreferFullHinting; + ++hintingPreference) { + for (quint32 ch=0x10330; ch<=0x1034A; ++ch) { + { + QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf"); + QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3") + .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(hintingPreference) + << ch + << true; + } + + { + QString fileName = QString::fromLatin1(SRCDIR "testfont_bold_italic.ttf"); + QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3") + .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(hintingPreference) + << ch + << false; + } + } + } +} + +void tst_QRawFont::supportsUcs4Character() +{ + QFETCH(QString, fileName); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(quint32, ucs4); + QFETCH(bool, shouldBeSupported); + + QRawFont font(fileName, 10, hintingPreference); + QVERIFY(font.isValid()); + + QCOMPARE(font.supportsCharacter(ucs4), shouldBeSupported); +} + +void tst_QRawFont::fromFont_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("hintingPreference"); + QTest::addColumn("familyName"); + QTest::addColumn("writingSystem"); + + for (int i=QFont::PreferDefaultHinting; i<=QFont::PreferFullHinting; ++i) { + QString titleBase = QString::fromLatin1("%2, hintingPreference=%1, writingSystem=%3") + .arg(i); + { + QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf"); + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Any; + + QString title = titleBase.arg(fileName).arg(writingSystem); + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(i) + << "QtBidiTestFont" + << writingSystem; + } + + { + QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf"); + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Hebrew; + + QString title = titleBase.arg(fileName).arg(writingSystem); + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(i) + << "QtBidiTestFont" + << writingSystem; + } + + { + QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf"); + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Latin; + + QString title = titleBase.arg(fileName).arg(writingSystem); + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(i) + << "QtBidiTestFont" + << writingSystem; + } + } +} + +void tst_QRawFont::fromFont() +{ + QFETCH(QString, fileName); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(QString, familyName); + QFETCH(QFontDatabase::WritingSystem, writingSystem); + + QFontDatabase fontDatabase; + int id = fontDatabase.addApplicationFont(fileName); + QVERIFY(id >= 0); + + QFont font(familyName); + font.setHintingPreference(hintingPreference); + font.setPixelSize(26); + + QRawFont rawFont = QRawFont::fromFont(font, writingSystem); + QVERIFY(rawFont.isValid()); + QCOMPARE(rawFont.familyName(), familyName); + QCOMPARE(rawFont.pixelSize(), 26); + + QVERIFY(fontDatabase.removeApplicationFont(id)); +} + +void tst_QRawFont::copyConstructor_data() +{ + QTest::addColumn("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting preference") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting preference") << QFont::PreferFullHinting; +} + +void tst_QRawFont::copyConstructor() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + { + QString rawFontFamilyName; + int rawFontPixelSize; + qreal rawFontAscent; + qreal rawFontDescent; + int rawFontTableSize; + + QRawFont outerRawFont; + { + QRawFont rawFont(QString::fromLatin1(SRCDIR "testfont.ttf"), 11, hintingPreference); + QVERIFY(rawFont.isValid()); + + rawFontFamilyName = rawFont.familyName(); + rawFontPixelSize = rawFont.pixelSize(); + rawFontAscent = rawFont.ascent(); + rawFontDescent = rawFont.descent(); + rawFontTableSize = rawFont.fontTable("glyf").size(); + QVERIFY(rawFontTableSize > 0); + + { + QRawFont otherRawFont(rawFont); + QVERIFY(otherRawFont.isValid()); + QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); + QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); + QCOMPARE(otherRawFont.ascent(), rawFontAscent); + QCOMPARE(otherRawFont.descent(), rawFontDescent); + QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); + } + + { + QRawFont otherRawFont = rawFont; + QVERIFY(otherRawFont.isValid()); + QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); + QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); + QCOMPARE(otherRawFont.ascent(), rawFontAscent); + QCOMPARE(otherRawFont.descent(), rawFontDescent); + QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); + } + + outerRawFont = rawFont; + } + + QVERIFY(outerRawFont.isValid()); + QCOMPARE(outerRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(outerRawFont.familyName(), rawFontFamilyName); + QCOMPARE(outerRawFont.hintingPreference(), hintingPreference); + QCOMPARE(outerRawFont.ascent(), rawFontAscent); + QCOMPARE(outerRawFont.descent(), rawFontDescent); + QCOMPARE(outerRawFont.fontTable("glyf").size(), rawFontTableSize); + } +} + +void tst_QRawFont::detach_data() +{ + QTest::addColumn("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting preference") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting preference") << QFont::PreferFullHinting; +} + +void tst_QRawFont::detach() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + { + QString rawFontFamilyName; + int rawFontPixelSize; + qreal rawFontAscent; + qreal rawFontDescent; + int rawFontTableSize; + + QRawFont outerRawFont; + { + QRawFont rawFont(QString::fromLatin1(SRCDIR "testfont.ttf"), 11, hintingPreference); + QVERIFY(rawFont.isValid()); + + rawFontFamilyName = rawFont.familyName(); + rawFontPixelSize = rawFont.pixelSize(); + rawFontAscent = rawFont.ascent(); + rawFontDescent = rawFont.descent(); + rawFontTableSize = rawFont.fontTable("glyf").size(); + QVERIFY(rawFontTableSize > 0); + + { + QRawFont otherRawFont(rawFont); + + otherRawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), + rawFontPixelSize, hintingPreference); + + QVERIFY(otherRawFont.isValid()); + QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); + QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); + QCOMPARE(otherRawFont.ascent(), rawFontAscent); + QCOMPARE(otherRawFont.descent(), rawFontDescent); + QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); + } + + { + QRawFont otherRawFont = rawFont; + + otherRawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), + rawFontPixelSize, hintingPreference); + + QVERIFY(otherRawFont.isValid()); + QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); + QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); + QCOMPARE(otherRawFont.ascent(), rawFontAscent); + QCOMPARE(otherRawFont.descent(), rawFontDescent); + QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); + } + + outerRawFont = rawFont; + + rawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), rawFontPixelSize, + hintingPreference); + } + + QVERIFY(outerRawFont.isValid()); + QCOMPARE(outerRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(outerRawFont.familyName(), rawFontFamilyName); + QCOMPARE(outerRawFont.hintingPreference(), hintingPreference); + QCOMPARE(outerRawFont.ascent(), rawFontAscent); + QCOMPARE(outerRawFont.descent(), rawFontDescent); + QCOMPARE(outerRawFont.fontTable("glyf").size(), rawFontTableSize); + } +} + +void tst_QRawFont::unsupportedWritingSystem_data() +{ + QTest::addColumn("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting preference") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting preference") << QFont::PreferFullHinting; +} + +void tst_QRawFont::unsupportedWritingSystem() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QFontDatabase fontDatabase; + int id = fontDatabase.addApplicationFont(QLatin1String(SRCDIR "testfont.ttf")); + + QFont font("QtBidiTestFont"); + font.setHintingPreference(hintingPreference); + font.setPixelSize(12); + + QRawFont rawFont = QRawFont::fromFont(font, QFontDatabase::Any); + QCOMPARE(rawFont.familyName(), QString::fromLatin1("QtBidiTestFont")); + QCOMPARE(rawFont.pixelSize(), 12); + + rawFont = QRawFont::fromFont(font, QFontDatabase::Hebrew); + QCOMPARE(rawFont.familyName(), QString::fromLatin1("QtBidiTestFont")); + QCOMPARE(rawFont.pixelSize(), 12); + + QString arabicText = QFontDatabase::writingSystemSample(QFontDatabase::Arabic); + + QTextLayout layout; + layout.setFont(font); + layout.setText(arabicText); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList glyphss = layout.glyphs(); + QCOMPARE(glyphss.size(), 1); + + QGlyphs glyphs = glyphss.at(0); + QRawFont layoutFont = glyphs.font(); + QVERIFY(layoutFont.familyName() != QString::fromLatin1("QtBidiTestFont")); + QCOMPARE(layoutFont.pixelSize(), 12); + + rawFont = QRawFont::fromFont(font, QFontDatabase::Arabic); + QCOMPARE(rawFont.familyName(), layoutFont.familyName()); + QCOMPARE(rawFont.pixelSize(), 12); + + fontDatabase.removeApplicationFont(id); +} + +QTEST_MAIN(tst_QRawFont) +#include "tst_qrawfont.moc" + +#endif // QT_NO_RAWFONT -- cgit v0.12 From 5a35876226939167f664b826807d511a81167b24 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 18 Apr 2011 09:51:13 +0200 Subject: Make sure #ifdef'd tests still have main() function Otherwise it won't link on QWS Reviewed-by: TrustMe --- tests/auto/qglyphs/tst_qglyphs.cpp | 10 +++++++--- tests/auto/qrawfont/tst_qrawfont.cpp | 8 +++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/auto/qglyphs/tst_qglyphs.cpp b/tests/auto/qglyphs/tst_qglyphs.cpp index a9ae556..ffa0d00 100644 --- a/tests/auto/qglyphs/tst_qglyphs.cpp +++ b/tests/auto/qglyphs/tst_qglyphs.cpp @@ -46,14 +46,13 @@ #include #include -#if !defined(QT_NO_RAWFONT) - // #define DEBUG_SAVE_IMAGE class tst_QGlyphs: public QObject { Q_OBJECT +#if !defined(QT_NO_RAWFONT) private slots: void initTestCase(); void cleanupTestCase(); @@ -77,8 +76,12 @@ private slots: private: int m_testFontId; QFont m_testFont; +#endif // QT_NO_RAWFONT + }; +#if !defined(QT_NO_RAWFONT) + Q_DECLARE_METATYPE(QGlyphs); void tst_QGlyphs::initTestCase() @@ -572,7 +575,8 @@ void tst_QGlyphs::drawRightToLeft() } +#endif // QT_NO_RAWFONT + QTEST_MAIN(tst_QGlyphs) #include "tst_qglyphs.moc" -#endif // QT_NO_RAWFONT diff --git a/tests/auto/qrawfont/tst_qrawfont.cpp b/tests/auto/qrawfont/tst_qrawfont.cpp index c20b41d..3aa4006 100644 --- a/tests/auto/qrawfont/tst_qrawfont.cpp +++ b/tests/auto/qrawfont/tst_qrawfont.cpp @@ -44,12 +44,11 @@ #include #include -#if !defined(QT_NO_RAWFONT) - class tst_QRawFont: public QObject { Q_OBJECT +#if !defined(QT_NO_RAWFONT) private slots: void invalidRawFont(); @@ -92,8 +91,10 @@ private slots: void unsupportedWritingSystem_data(); void unsupportedWritingSystem(); +#endif // QT_NO_RAWFONT }; +#if !defined(QT_NO_RAWFONT) Q_DECLARE_METATYPE(QFont::HintingPreference) Q_DECLARE_METATYPE(QFont::Style) Q_DECLARE_METATYPE(QFont::Weight) @@ -806,7 +807,8 @@ void tst_QRawFont::unsupportedWritingSystem() fontDatabase.removeApplicationFont(id); } +#endif // QT_NO_RAWFONT + QTEST_MAIN(tst_QRawFont) #include "tst_qrawfont.moc" -#endif // QT_NO_RAWFONT -- cgit v0.12 From 3c659eb590aecbcdb40cb498901e757e780fa892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 18 Apr 2011 10:31:05 +0200 Subject: Made linearGradientSymmetry test pass on qreal=float platforms. We need to loosen the requirements a bit when qreal is float... Just skip the two failing test cases for now. Reviewed-by: Eskil Abrahamsen Blomfeldt --- tests/auto/qpainter/tst_qpainter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/qpainter/tst_qpainter.cpp b/tests/auto/qpainter/tst_qpainter.cpp index fa80635..64dacec 100644 --- a/tests/auto/qpainter/tst_qpainter.cpp +++ b/tests/auto/qpainter/tst_qpainter.cpp @@ -3989,7 +3989,7 @@ void tst_QPainter::linearGradientSymmetry_data() { QTest::addColumn("stops"); - { + if (sizeof(qreal) != sizeof(float)) { QGradientStops stops; stops << qMakePair(qreal(0.0), QColor(Qt::blue)); stops << qMakePair(qreal(0.2), QColor(220, 220, 220, 0)); @@ -4006,7 +4006,7 @@ void tst_QPainter::linearGradientSymmetry_data() QTest::newRow("two stops") << stops; } - { + if (sizeof(qreal) != sizeof(float)) { QGradientStops stops; stops << qMakePair(qreal(0.3), QColor(Qt::blue)); stops << qMakePair(qreal(0.6), QColor(Qt::black)); -- cgit v0.12 From 4024a08239c3e69bb2e0ca045ccbdf3fc900f675 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Fri, 15 Apr 2011 15:05:03 +0200 Subject: Fix an race condition in the auto test. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deleting the page in the wizard without removing it first leads to a crash when the wizard tries to access a deleted page. Reviewed-by: Samuel Rødal --- tests/auto/qwizard/tst_qwizard.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/auto/qwizard/tst_qwizard.cpp b/tests/auto/qwizard/tst_qwizard.cpp index bbac8a3..5667d40 100644 --- a/tests/auto/qwizard/tst_qwizard.cpp +++ b/tests/auto/qwizard/tst_qwizard.cpp @@ -2551,8 +2551,8 @@ void tst_QWizard::task177022_setFixedSize() QWizard wiz; QWizardPage page1; QWizardPage page2; - wiz.addPage(&page1); - wiz.addPage(&page2); + int page1_id = wiz.addPage(&page1); + int page2_id = wiz.addPage(&page2); wiz.setFixedSize(width, height); if (wiz.wizardStyle() == QWizard::AeroStyle) QEXPECT_FAIL("", "this probably relates to non-client area hack for AeroStyle titlebar " @@ -2579,6 +2579,8 @@ void tst_QWizard::task177022_setFixedSize() QCOMPARE(wiz.maximumWidth(), width); QCOMPARE(wiz.maximumHeight(), height); + wiz.removePage(page1_id); + wiz.removePage(page2_id); } void tst_QWizard::task248107_backButton() -- cgit v0.12 From 3197fe2af911673c6291db0102e90a0d7f6ae926 Mon Sep 17 00:00:00 2001 From: Fabien Freling Date: Mon, 18 Apr 2011 11:49:57 +0200 Subject: Revert "Switch the default graphics system to raster on Mac." This reverts commit a5d40fd3814ab7c8e865912c03a918bfd5994998. We have to fix the regressions due to the raster engine before putting it by default. --- src/gui/painting/qgraphicssystemfactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/painting/qgraphicssystemfactory.cpp b/src/gui/painting/qgraphicssystemfactory.cpp index 6212674..62a60d7 100644 --- a/src/gui/painting/qgraphicssystemfactory.cpp +++ b/src/gui/painting/qgraphicssystemfactory.cpp @@ -74,7 +74,7 @@ QGraphicsSystem *QGraphicsSystemFactory::create(const QString& key) if (system.isEmpty()) { system = QLatin1String("runtime"); } -#elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) && !defined(Q_OS_SYMBIAN) || defined(Q_WS_X11) || (defined (Q_WS_MAC) && defined(QT_MAC_USE_COCOA)) +#elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) && !defined(Q_OS_SYMBIAN) || defined(Q_WS_X11) if (system.isEmpty()) { system = QLatin1String("raster"); } -- cgit v0.12 From e004701bd7ba9e4a7cd5ac1bf784829feae16cae Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Mon, 18 Apr 2011 11:21:16 +0200 Subject: Disable tst_QPixmap::onlyNullPixmapsOutsideGuiThread on Mac No need to check it anymore after the switch to raster engine. Reviewed-by: Eskil --- tests/auto/qpixmap/tst_qpixmap.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/qpixmap/tst_qpixmap.cpp b/tests/auto/qpixmap/tst_qpixmap.cpp index 4d032e8..4ba51de 100644 --- a/tests/auto/qpixmap/tst_qpixmap.cpp +++ b/tests/auto/qpixmap/tst_qpixmap.cpp @@ -1337,7 +1337,7 @@ void tst_QPixmap::toSymbianCFbsBitmap() void tst_QPixmap::onlyNullPixmapsOutsideGuiThread() { -#if !defined(Q_WS_WIN) +#if !defined(Q_WS_WIN) && !defined(Q_WS_MAC) class Thread : public QThread { public: @@ -1370,7 +1370,7 @@ void tst_QPixmap::onlyNullPixmapsOutsideGuiThread() thread.wait(); #endif -#endif // !defined(Q_WS_WIN) +#endif // !defined(Q_WS_WIN) && !defined(Q_WS_MAC) } void tst_QPixmap::refUnref() -- cgit v0.12 From 518c2a58ed6fdfd7449cb4476aa8ea0d32ad16e3 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 18 Apr 2011 14:54:24 +0200 Subject: Fix missing color in text when using static text back-end in QML Using QStaticTextItem as a back-end for QML text on GL caused a regression where parts of a text element would get the wrong color. This was because the color set on the painter which was passed into draw() was never transferred to the painter used to record the draw text calls issued by the underlying QTextLayout::draw()-function. Task-number: QTBUG-18428 Reviewed-by: Jiang Jiang --- src/declarative/graphicsitems/qdeclarativetextlayout.cpp | 5 +++-- src/declarative/graphicsitems/qdeclarativetextlayout_p.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp index 31819f5..c5f40b3 100644 --- a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp @@ -299,7 +299,7 @@ void QDeclarativeTextLayout::clearLayout() QTextLayout::clearLayout(); } -void QDeclarativeTextLayout::prepare() +void QDeclarativeTextLayout::prepare(QPainter *painter) { if (!d || !d->cached) { @@ -308,6 +308,7 @@ void QDeclarativeTextLayout::prepare() InertTextPainter *itp = inertTextPainter(); itp->device.begin(d); + itp->painter.setPen(painter->pen()); QTextLayout::draw(&itp->painter, QPointF(0, 0)); glyph_t *glyphPool = d->glyphs.data(); @@ -340,7 +341,7 @@ void QDeclarativeTextLayout::draw(QPainter *painter, const QPointF &p) return; } - prepare(); + prepare(painter); int itemCount = d->items.count(); diff --git a/src/declarative/graphicsitems/qdeclarativetextlayout_p.h b/src/declarative/graphicsitems/qdeclarativetextlayout_p.h index 2c9264e..23b22a6 100644 --- a/src/declarative/graphicsitems/qdeclarativetextlayout_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextlayout_p.h @@ -61,7 +61,7 @@ public: void beginLayout(); void clearLayout(); - void prepare(); + void prepare(QPainter *); void draw(QPainter *, const QPointF & = QPointF()); private: -- cgit v0.12 From 62e87f8597f6c1c7622125a26747636d61a6c7ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 18 Apr 2011 15:23:55 +0200 Subject: Fixes compilation of wayland plugin after latest changes in wayland. --- src/plugins/platforms/wayland/qwaylandbuffer.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/platforms/wayland/qwaylandbuffer.h b/src/plugins/platforms/wayland/qwaylandbuffer.h index 8779d5f..faeb3e8 100644 --- a/src/plugins/platforms/wayland/qwaylandbuffer.h +++ b/src/plugins/platforms/wayland/qwaylandbuffer.h @@ -44,6 +44,7 @@ #include +#include #include class QWaylandBuffer { -- cgit v0.12 From 1d28996fd635eed07eff61502ab67f7158ba43cd Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 18 Apr 2011 15:20:11 +0200 Subject: Support text decoration in QML when using static text back-end When the QStaticTextItem code path in QML was copy-pasted, QStaticText did not support text decoration yet. It has since been implemented. We copy-paste the fix as well (which means we have to export a private function from QtGui to avoid duplicating that code as well.) Task-number: QTBUG-18428 Reviewed-by: Jiang Jiang --- .../graphicsitems/qdeclarativetextlayout.cpp | 10 ++++++++++ src/gui/painting/qpainter.cpp | 22 +++++++++++----------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp index c5f40b3..75d9f67 100644 --- a/src/declarative/graphicsitems/qdeclarativetextlayout.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextlayout.cpp @@ -327,6 +327,12 @@ void QDeclarativeTextLayout::prepare(QPainter *painter) } } +// Defined in qpainter.cpp +extern Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray, + const QFixedPoint *positions, int glyphCount, + QFontEngine *fontEngine, const QFont &font, + const QTextCharFormat &charFormat); + void QDeclarativeTextLayout::draw(QPainter *painter, const QPointF &p) { QPainterPrivate *priv = QPainterPrivate::get(painter); @@ -372,6 +378,10 @@ void QDeclarativeTextLayout::draw(QPainter *painter, const QPointF &p) currentColor = item.color; } priv->extended->drawStaticTextItem(&item); + + qt_draw_decoration_for_glyphs(painter, item.glyphs, item.glyphPositions, + item.numGlyphs, item.fontEngine(), painter->font(), + QTextCharFormat()); } if (currentColor != oldPen.color()) painter->setPen(oldPen); diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 76ac7db..0e279c9 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -95,10 +95,10 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const const QTextItem::RenderFlags flags, qreal width, const QTextCharFormat &charFormat); // Helper function to calculate left most position, width and flags for decoration drawing -static void drawDecorationForGlyphs(QPainter *painter, const glyph_t *glyphArray, - const QFixedPoint *positions, int glyphCount, - QFontEngine *fontEngine, const QFont &font, - const QTextCharFormat &charFormat); +Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray, + const QFixedPoint *positions, int glyphCount, + QFontEngine *fontEngine, const QFont &font, + const QTextCharFormat &charFormat); static inline QGradient::CoordinateMode coordinateMode(const QBrush &brush) { @@ -5937,9 +5937,9 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText } d->extended->drawStaticTextItem(item); - drawDecorationForGlyphs(this, item->glyphs, item->glyphPositions, - item->numGlyphs, item->fontEngine(), staticText_d->font, - QTextCharFormat()); + qt_draw_decoration_for_glyphs(this, item->glyphs, item->glyphPositions, + item->numGlyphs, item->fontEngine(), staticText_d->font, + QTextCharFormat()); } if (currentColor != oldPen.color()) setPen(oldPen); @@ -6383,10 +6383,10 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const painter->setBrush(oldBrush); } -static void drawDecorationForGlyphs(QPainter *painter, const glyph_t *glyphArray, - const QFixedPoint *positions, int glyphCount, - QFontEngine *fontEngine, const QFont &font, - const QTextCharFormat &charFormat) +Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray, + const QFixedPoint *positions, int glyphCount, + QFontEngine *fontEngine, const QFont &font, + const QTextCharFormat &charFormat) { if (!(font.underline() || font.strikeOut() || font.overline())) return; -- cgit v0.12 From 13190f3a8593b1b255929ebc52c9ad95a21b4669 Mon Sep 17 00:00:00 2001 From: con Date: Mon, 18 Apr 2011 16:12:15 +0200 Subject: Compile fix for QPA's session manager. Include QApplication, so the compiler definitely knows that it's a QObject. Reviewed-by: Paul Olav Tvete --- src/gui/kernel/qsessionmanager_qpa.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/kernel/qsessionmanager_qpa.cpp b/src/gui/kernel/qsessionmanager_qpa.cpp index ef532d7..68685b4 100644 --- a/src/gui/kernel/qsessionmanager_qpa.cpp +++ b/src/gui/kernel/qsessionmanager_qpa.cpp @@ -42,6 +42,8 @@ #include #include +#include + #ifndef QT_NO_SESSIONMANAGER QT_BEGIN_NAMESPACE -- cgit v0.12 From c480dd641f5d22d1ee72cb27bf39e24c6df65658 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Wed, 15 Dec 2010 15:11:45 +0100 Subject: Support visual cursor movement for BIDI text Bidi input can in some contexts be more intuitive if the cursor works in visual way: pressing left arrow key always make cursor move one character to the left regardless the language of text, pressing right arrow key always make cursor move to the right. It is also the behavior of Mac OS X. Based on the above reason and requests from Symbian we implemented this support for visual movement in BIDI text. 3 public properties are added to QTextDocument, QTextLayout and QLineEdit respectively: - QTextDocument::defaultCursorMoveStyle can be used to control the cursor behavior in all widgets based on QTextDocument, like QTextEdit, QPlainTextEdit, etc. When set to QTextCursor:: Visual, it will enable visual movement for all the cursors in the corresponding text edit. Default is QTextCursor::Logical. - QTextLayout::cursorMoveStyle is used for low-level cursor manipulation. When set to Visual, it will enable visual movement behavior for all the cursor related methods, including cursorToX, xToCursor and drawCursor. Default is Logical. - QLineEdit::cursorMoveStyle is used to control cursor movement behavior in QLineEdit. Default is Logical.: Task-number: QTBUG-13859 Reviewed-by: Eskil --- src/gui/text/qtextcursor.cpp | 42 ++- src/gui/text/qtextcursor.h | 4 + src/gui/text/qtextdocument.cpp | 23 ++ src/gui/text/qtextdocument.h | 5 +- src/gui/text/qtextdocument_p.cpp | 15 + src/gui/text/qtextdocument_p.h | 4 + src/gui/text/qtextengine.cpp | 297 ++++++++++++++++++++ src/gui/text/qtextengine_p.h | 60 ++++ src/gui/text/qtextlayout.cpp | 394 ++++++++++----------------- src/gui/text/qtextlayout.h | 6 + src/gui/widgets/qlinecontrol.cpp | 9 +- src/gui/widgets/qlinecontrol_p.h | 8 +- src/gui/widgets/qlineedit.cpp | 28 ++ src/gui/widgets/qlineedit.h | 4 + tests/auto/qcomplextext/tst_qcomplextext.cpp | 87 ++++++ tests/auto/qlineedit/tst_qlineedit.cpp | 136 +++++++++ tests/auto/qtextedit/tst_qtextedit.cpp | 149 +++++++++- 17 files changed, 998 insertions(+), 273 deletions(-) diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp index 6ddfdb0..4f6857a 100644 --- a/src/gui/text/qtextcursor.cpp +++ b/src/gui/text/qtextcursor.cpp @@ -362,20 +362,23 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor currentCharFormat = -1; bool adjustX = true; QTextBlock blockIt = block(); + bool visualMovement = priv->defaultCursorMoveStyle == QTextCursor::Visual; if (!blockIt.isValid()) return false; - if (op >= QTextCursor::Left && op <= QTextCursor::WordRight - && blockIt.textDirection() == Qt::RightToLeft) { - if (op == QTextCursor::Left) - op = QTextCursor::NextCharacter; - else if (op == QTextCursor::Right) - op = QTextCursor::PreviousCharacter; - else if (op == QTextCursor::WordLeft) + if (blockIt.textDirection() == Qt::RightToLeft) { + if (op == QTextCursor::WordLeft) op = QTextCursor::NextWord; else if (op == QTextCursor::WordRight) op = QTextCursor::PreviousWord; + + if (!visualMovement) { + if (op == QTextCursor::Left) + op = QTextCursor::NextCharacter; + else if (op == QTextCursor::Right) + op = QTextCursor::PreviousCharacter; + } } const QTextLayout *layout = blockLayout(blockIt); @@ -418,9 +421,12 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor break; } case QTextCursor::PreviousCharacter: - case QTextCursor::Left: newPosition = priv->previousCursorPosition(position, QTextLayout::SkipCharacters); break; + case QTextCursor::Left: + newPosition = visualMovement ? priv->leftCursorPosition(position) + : priv->previousCursorPosition(position, QTextLayout::SkipCharacters); + break; case QTextCursor::StartOfWord: { if (relativePos == 0) break; @@ -529,9 +535,12 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor break; } case QTextCursor::NextCharacter: - case QTextCursor::Right: newPosition = priv->nextCursorPosition(position, QTextLayout::SkipCharacters); break; + case QTextCursor::Right: + newPosition = visualMovement ? priv->rightCursorPosition(position) + : priv->nextCursorPosition(position, QTextLayout::SkipCharacters); + break; case QTextCursor::NextWord: case QTextCursor::WordRight: newPosition = priv->nextCursorPosition(position, QTextLayout::SkipWords); @@ -2558,4 +2567,19 @@ QTextDocument *QTextCursor::document() const return 0; // document went away } +/*! + \enum QTextCursor::MoveStyle + + This enum describes the movement style available to QTextCursor. The options + are: + + \value Logical Within a left-to-right text block, increase cursor position + when pressing left arrow key, decrease cursor position when pressing the + right arrow key. If the text block is right-to-left, the opposite behavior + applies. + \value Visual Pressing the left arrow key will always cause the cursor to move + left, regardless of the text's writing direction. The same behavior applies to + right arrow key. +*/ + QT_END_NAMESPACE diff --git a/src/gui/text/qtextcursor.h b/src/gui/text/qtextcursor.h index 4eaeb41..30f8272 100644 --- a/src/gui/text/qtextcursor.h +++ b/src/gui/text/qtextcursor.h @@ -86,6 +86,10 @@ public: MoveAnchor, KeepAnchor }; + enum MoveStyle { + Logical, + Visual, + }; void setPosition(int pos, MoveMode mode = MoveAnchor); int position() const; diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 6dbd755..36f3c6c 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -586,6 +586,29 @@ void QTextDocument::setDefaultTextOption(const QTextOption &option) } /*! + \since 4.8 + + The default cursor movement style is used by all QTextCursor objects + created from the document. The default is QTextCursor::Logical. +*/ +QTextCursor::MoveStyle QTextDocument::defaultCursorMoveStyle() const +{ + Q_D(const QTextDocument); + return d->defaultCursorMoveStyle; +} + +/*! + \since 4.8 + + Set the default cursor movement style. +*/ +void QTextDocument::setDefaultCursorMoveStyle(QTextCursor::MoveStyle style) +{ + Q_D(QTextDocument); + d->defaultCursorMoveStyle = style; +} + +/*! \fn void QTextDocument::markContentsDirty(int position, int length) Marks the contents specified by the given \a position and \a length diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h index f87ccc9..e515b36 100644 --- a/src/gui/text/qtextdocument.h +++ b/src/gui/text/qtextdocument.h @@ -46,6 +46,7 @@ #include #include #include +#include QT_BEGIN_HEADER @@ -60,7 +61,6 @@ class QPainter; class QPrinter; class QAbstractTextDocumentLayout; class QPoint; -class QTextCursor; class QTextObject; class QTextFormat; class QTextFrame; @@ -269,6 +269,9 @@ public: QTextOption defaultTextOption() const; void setDefaultTextOption(const QTextOption &option); + QTextCursor::MoveStyle defaultCursorMoveStyle() const; + void setDefaultCursorMoveStyle(QTextCursor::MoveStyle style); + Q_SIGNALS: void contentsChange(int from, int charsRemoves, int charsAdded); void contentsChanged(); diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp index 2172f74..71af89f 100644 --- a/src/gui/text/qtextdocument_p.cpp +++ b/src/gui/text/qtextdocument_p.cpp @@ -209,6 +209,7 @@ QTextDocumentPrivate::QTextDocumentPrivate() defaultTextOption.setTabStop(80); // same as in qtextengine.cpp defaultTextOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + defaultCursorMoveStyle = QTextCursor::Logical; indentWidth = 40; documentMargin = 4; @@ -1382,6 +1383,20 @@ int QTextDocumentPrivate::previousCursorPosition(int position, QTextLayout::Curs return it.layout()->previousCursorPosition(position-start, mode) + start; } +int QTextDocumentPrivate::leftCursorPosition(int position) const +{ + QTextBlock it = blocksFind(position); + int start = it.position(); + return it.layout()->leftCursorPosition(position-start) + start; +} + +int QTextDocumentPrivate::rightCursorPosition(int position) const +{ + QTextBlock it = blocksFind(position); + int start = it.position(); + return it.layout()->rightCursorPosition(position-start) + start; +} + void QTextDocumentPrivate::changeObjectFormat(QTextObject *obj, int format) { beginEditBlock(); diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h index b464f2e..6563920 100644 --- a/src/gui/text/qtextdocument_p.h +++ b/src/gui/text/qtextdocument_p.h @@ -64,6 +64,7 @@ #include "private/qtextformat_p.h" #include "QtGui/qtextdocument.h" #include "QtGui/qtextobject.h" +#include "QtGui/qtextcursor.h" #include "QtCore/qmap.h" #include "QtCore/qvariant.h" #include "QtCore/qurl.h" @@ -244,6 +245,8 @@ public: int nextCursorPosition(int position, QTextLayout::CursorMode mode) const; int previousCursorPosition(int position, QTextLayout::CursorMode mode) const; + int leftCursorPosition(int position) const; + int rightCursorPosition(int position) const; void changeObjectFormat(QTextObject *group, int format); @@ -339,6 +342,7 @@ private: public: QTextOption defaultTextOption; + QTextCursor::MoveStyle defaultCursorMoveStyle; #ifndef QT_NO_CSSPARSER QCss::StyleSheet parsedDefaultStyleSheet; #endif diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 08d0eca..0e649f0 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1304,6 +1304,7 @@ static void init(QTextEngine *e) e->ignoreBidi = false; e->cacheGlyphs = false; e->forceJustification = false; + e->visualMovement = false; e->layoutData = 0; @@ -2737,6 +2738,180 @@ QFixed QTextEngine::leadingSpaceWidth(const QScriptLine &line) return width(line.from + pos, line.length - pos); } +QFixed QTextEngine::alignLine(const QScriptLine &line) +{ + QFixed x = 0; + justify(line); + // if width is QFIXED_MAX that means we used setNumColumns() and that implicitly makes this line left aligned. + if (!line.justified && line.width != QFIXED_MAX) { + int align = option.alignment(); + if (align & Qt::AlignJustify && isRightToLeft()) + align = Qt::AlignRight; + if (align & Qt::AlignRight) + x = line.width - (line.textAdvance + leadingSpaceWidth(line)); + else if (align & Qt::AlignHCenter) + x = (line.width - line.textAdvance)/2; + } + return x; +} + +QFixed QTextEngine::offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos) +{ + unsigned short *logClusters = this->logClusters(si); + const QGlyphLayout &glyphs = shapedGlyphs(si); + + int offsetInCluster = 0; + for (int i = pos - 1; i >= 0; i--) { + if (logClusters[i] == glyph_pos) + offsetInCluster++; + else + break; + } + + // in the case that the offset is inside a (multi-character) glyph, + // interpolate the position. + if (offsetInCluster > 0) { + int clusterLength = 0; + for (int i = pos - offsetInCluster; i < max; i++) { + if (logClusters[i] == glyph_pos) + clusterLength++; + else + break; + } + if (clusterLength) + return glyphs.advances_x[glyph_pos] * offsetInCluster / clusterLength; + } + + return 0; +} + +int QTextEngine::previousLogicalPosition(int oldPos) const +{ + const HB_CharAttributes *attrs = attributes(); + if (!attrs || oldPos < 0) + return oldPos; + + if (oldPos <= 0) + return 0; + oldPos--; + while (oldPos && !attrs[oldPos].charStop) + oldPos--; + return oldPos; +} + +int QTextEngine::nextLogicalPosition(int oldPos) const +{ + const HB_CharAttributes *attrs = attributes(); + int len = block.isValid() ? block.length() - 1 + : layoutData->string.length(); + Q_ASSERT(len <= layoutData->string.length()); + if (!attrs || oldPos < 0 || oldPos >= len) + return oldPos; + + oldPos++; + while (oldPos < len && !attrs[oldPos].charStop) + oldPos++; + return oldPos; +} + +int QTextEngine::lineNumberForTextPosition(int pos) +{ + if (!layoutData) + itemize(); + if (pos == layoutData->string.length() && lines.size()) + return lines.size() - 1; + for (int i = 0; i < lines.size(); ++i) { + const QScriptLine& line = lines[i]; + if (line.from + line.length > pos) + return i; + } + return -1; +} + +void QTextEngine::insertionPointsForLine(int lineNum, QVector &insertionPoints) +{ + QTextLineItemIterator iterator(this, lineNum); + bool rtl = isRightToLeft(); + bool lastLine = lineNum >= lines.size() - 1; + + while (!iterator.atEnd()) { + iterator.next(); + const QScriptItem *si = &layoutData->items[iterator.item]; + if (si->analysis.bidiLevel % 2) { + int i = iterator.itemEnd - 1, min = iterator.itemStart; + if (lastLine && (rtl ? iterator.atBeginning() : iterator.atEnd())) + i++; + for (; i >= min; i--) + insertionPoints.push_back(i); + } else { + int i = iterator.itemStart, max = iterator.itemEnd; + if (lastLine && (rtl ? iterator.atBeginning() : iterator.atEnd())) + max++; + for (; i < max; i++) + insertionPoints.push_back(i); + } + } +} + +int QTextEngine::endOfLine(int lineNum) +{ + QVector insertionPoints; + insertionPointsForLine(lineNum, insertionPoints); + + if (insertionPoints.size() > 0) + return insertionPoints.last(); + return 0; +} + +int QTextEngine::beginningOfLine(int lineNum) +{ + QVector insertionPoints; + insertionPointsForLine(lineNum, insertionPoints); + + if (insertionPoints.size() > 0) + return insertionPoints.first(); + return 0; +} + +int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation op) +{ + if (!layoutData) + itemize(); + + bool moveRight = (op == QTextCursor::Right); + bool alignRight = isRightToLeft(); + if (!layoutData->hasBidi) + return moveRight ^ alignRight ? nextLogicalPosition(pos) : previousLogicalPosition(pos); + + int lineNum = lineNumberForTextPosition(pos); + Q_ASSERT(lineNum >= 0); + + QVector insertionPoints; + insertionPointsForLine(lineNum, insertionPoints); + int i, max = insertionPoints.size(); + for (i = 0; i < max; i++) + if (pos == insertionPoints[i]) { + if (moveRight) { + if (i + 1 < max) + return insertionPoints[i + 1]; + } else { + if (i > 0) + return insertionPoints[i - 1]; + } + + if (moveRight ^ alignRight) { + if (lineNum + 1 < lines.size()) + return alignRight ? endOfLine(lineNum + 1) : beginningOfLine(lineNum + 1); + } + else { + if (lineNum > 0) + return alignRight ? beginningOfLine(lineNum - 1) : endOfLine(lineNum - 1); + } + } + + return pos; +} + QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f) : QTextEngine(string, f), _layoutData(string, _memory, MemSize) @@ -2841,5 +3016,127 @@ glyph_metrics_t glyph_metrics_t::transformed(const QTransform &matrix) const return m; } +QTextLineItemIterator::QTextLineItemIterator(QTextEngine *_eng, int _lineNum, const QPointF &pos, + const QTextLayout::FormatRange *_selection) + : eng(_eng), + line(eng->lines[_lineNum]), + si(0), + lineNum(_lineNum), + lineEnd(line.from + line.length), + firstItem(eng->findItem(line.from)), + lastItem(eng->findItem(lineEnd - 1)), + nItems((firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0), + logicalItem(-1), + item(-1), + visualOrder(nItems), + levels(nItems), + selection(_selection) +{ + pos_x = x = QFixed::fromReal(pos.x()); + + x += line.x; + + x += eng->alignLine(line); + + for (int i = 0; i < nItems; ++i) + levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel; + QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); + + eng->shapeLine(line); +} + +QScriptItem &QTextLineItemIterator::next() +{ + x += itemWidth; + + ++logicalItem; + item = visualOrder[logicalItem] + firstItem; + itemLength = eng->length(item); + si = &eng->layoutData->items[item]; + if (!si->num_glyphs) + eng->shape(item); + + if (si->analysis.flags >= QScriptAnalysis::TabOrObject) { + itemWidth = si->width; + return *si; + } + + unsigned short *logClusters = eng->logClusters(si); + QGlyphLayout glyphs = eng->shapedGlyphs(si); + + itemStart = qMax(line.from, si->position); + glyphsStart = logClusters[itemStart - si->position]; + if (lineEnd < si->position + itemLength) { + itemEnd = lineEnd; + glyphsEnd = logClusters[itemEnd-si->position]; + } else { + itemEnd = si->position + itemLength; + glyphsEnd = si->num_glyphs; + } + // show soft-hyphen at line-break + if (si->position + itemLength >= lineEnd + && eng->layoutData->string.at(lineEnd - 1) == 0x00ad) + glyphs.attributes[glyphsEnd - 1].dontPrint = false; + + itemWidth = 0; + for (int g = glyphsStart; g < glyphsEnd; ++g) + itemWidth += glyphs.effectiveAdvance(g); + + return *si; +} + +bool QTextLineItemIterator::getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const +{ + *selectionX = *selectionWidth = 0; + + if (!selection) + return false; + + if (si->analysis.flags >= QScriptAnalysis::TabOrObject) { + if (si->position >= selection->start + selection->length + || si->position + itemLength <= selection->start) + return false; + + *selectionX = x; + *selectionWidth = itemWidth; + } else { + unsigned short *logClusters = eng->logClusters(si); + QGlyphLayout glyphs = eng->shapedGlyphs(si); + + int from = qMax(itemStart, selection->start) - si->position; + int to = qMin(itemEnd, selection->start + selection->length) - si->position; + if (from >= to) + return false; + + int start_glyph = logClusters[from]; + int end_glyph = (to == eng->length(item)) ? si->num_glyphs : logClusters[to]; + QFixed soff; + QFixed swidth; + if (si->analysis.bidiLevel %2) { + for (int g = glyphsEnd - 1; g >= end_glyph; --g) + soff += glyphs.effectiveAdvance(g); + for (int g = end_glyph - 1; g >= start_glyph; --g) + swidth += glyphs.effectiveAdvance(g); + } else { + for (int g = glyphsStart; g < start_glyph; ++g) + soff += glyphs.effectiveAdvance(g); + for (int g = start_glyph; g < end_glyph; ++g) + swidth += glyphs.effectiveAdvance(g); + } + + // If the starting character is in the middle of a ligature, + // selection should only contain the right part of that ligature + // glyph, so we need to get the width of the left part here and + // add it to *selectionX + QFixed leftOffsetInLigature = eng->offsetInLigature(si, from, to, start_glyph); + *selectionX = x + soff + leftOffsetInLigature; + *selectionWidth = swidth - leftOffsetInLigature; + // If the ending character is also part of a ligature, swidth does + // not contain that part yet, we also need to find out the width of + // that left part + *selectionWidth += eng->offsetInLigature(si, to, eng->length(item), end_glyph); + } + return true; +} QT_END_NAMESPACE diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 366c5c3..c476485 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -64,6 +64,7 @@ #include "QtGui/qpaintengine.h" #include "QtGui/qtextobject.h" #include "QtGui/qtextoption.h" +#include "QtGui/qtextcursor.h" #include "QtCore/qset.h" #include "QtCore/qdebug.h" #ifndef QT_BUILD_COMPAT_LIB @@ -471,6 +472,7 @@ public: void shape(int item) const; void justify(const QScriptLine &si); + QFixed alignLine(const QScriptLine &line); QFixed width(int charFrom, int numChars) const; glyph_metrics_t boundingBox(int from, int len) const; @@ -586,12 +588,18 @@ public: uint cacheGlyphs : 1; uint stackEngine : 1; uint forceJustification : 1; + uint visualMovement : 1; int *underlinePositions; mutable LayoutData *layoutData; inline bool hasFormats() const { return (block.docHandle() || specialData); } + inline bool visualCursorMovement() const + { + return (visualMovement || + (block.docHandle() ? block.docHandle()->defaultCursorMoveStyle == QTextCursor::Visual : false)); + } struct SpecialData { int preeditPosition; @@ -611,6 +619,13 @@ public: void shapeLine(const QScriptLine &line); QFixed leadingSpaceWidth(const QScriptLine &line); + QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos); + int previousLogicalPosition(int oldPos) const; + int nextLogicalPosition(int oldPos) const; + int lineNumberForTextPosition(int pos); + int positionAfterVisualMovement(int oldPos, QTextCursor::MoveOperation op); + void insertionPointsForLine(int lineNum, QVector &insertionPoints); + private: void setBoundary(int strPos) const; void addRequiredBoundaries() const; @@ -625,6 +640,8 @@ private: void splitItem(int item, int pos) const; void resolveAdditionalFormats() const; + int endOfLine(int lineNum); + int beginningOfLine(int lineNum); }; class QStackTextEngine : public QTextEngine { @@ -635,6 +652,49 @@ public: void *_memory[MemSize]; }; +struct QTextLineItemIterator +{ + QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(), + const QTextLayout::FormatRange *_selection = 0); + + inline bool atEnd() const { return logicalItem >= nItems - 1; } + inline bool atBeginning() const { return logicalItem <= 0; } + QScriptItem &next(); + + bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const; + inline bool isOutsideSelection() const { + QFixed tmp1, tmp2; + return !getSelectionBounds(&tmp1, &tmp2); + } + + QTextEngine *eng; + + QFixed x; + QFixed pos_x; + const QScriptLine &line; + QScriptItem *si; + + int lineNum; + int lineEnd; + int firstItem; + int lastItem; + int nItems; + int logicalItem; + int item; + int itemLength; + + int glyphsStart; + int glyphsEnd; + int itemStart; + int itemEnd; + + QFixed itemWidth; + + QVarLengthArray visualOrder; + QVarLengthArray levels; + + const QTextLayout::FormatRange *selection; +}; Q_DECLARE_OPERATORS_FOR_FLAGS(QTextEngine::ShaperFlags) diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 93f71d3..bd224c6 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -72,23 +72,6 @@ QT_BEGIN_NAMESPACE #define SuppressText 0x5012 #define SuppressBackground 0x513 -static QFixed alignLine(QTextEngine *eng, const QScriptLine &line) -{ - QFixed x = 0; - eng->justify(line); - // if width is QFIXED_MAX that means we used setNumColumns() and that implicitly makes this line left aligned. - if (!line.justified && line.width != QFIXED_MAX) { - int align = eng->option.alignment(); - if (align & Qt::AlignJustify && eng->isRightToLeft()) - align = Qt::AlignRight; - if (align & Qt::AlignRight) - x = line.width - (line.textAdvance + eng->leadingSpaceWidth(line)); - else if (align & Qt::AlignHCenter) - x = (line.width - line.textAdvance)/2; - } - return x; -} - /*! \class QTextLayout::FormatRange \reentrant @@ -596,6 +579,30 @@ bool QTextLayout::cacheEnabled() const } /*! + Set the visual cursor movement style. If the QTextLayout is backed by + a document, you can ignore this and use the option in QTextDocument, + this option is for widgets like QLineEdit or custom widgets without + a QTextDocument. Default value is QTextCursor::Logical. + + \sa setCursorMoveStyle() +*/ +void QTextLayout::setCursorMoveStyle(QTextCursor::MoveStyle style) +{ + d->visualMovement = style == QTextCursor::Visual ? true : false; +} + +/*! + The cursor movement style of this QTextLayout. The default is + QTextCursor::Logical. + + \sa setCursorMoveStyle() +*/ +QTextCursor::MoveStyle QTextLayout::cursorMoveStyle() const +{ + return d->visualMovement ? QTextCursor::Visual : QTextCursor::Logical; +} + +/*! Begins the layout process. \sa endLayout() @@ -718,6 +725,34 @@ int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const } /*! + Returns the cursor position to the right of \a oldPos, next to it. + It's dependent on the visual position of characters, after bi-directional + reordering. + + \sa leftCursorPosition(), nextCursorPosition() +*/ +int QTextLayout::rightCursorPosition(int oldPos) const +{ + int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Right); +// qDebug("%d -> %d", oldPos, newPos); + return newPos; +} + +/*! + Returns the cursor position to the left of \a oldPos, next to it. + It's dependent on the visual position of characters, after bi-directional + reordering. + + \sa rightCursorPosition(), previousCursorPosition() +*/ +int QTextLayout::leftCursorPosition(int oldPos) const +{ + int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Left); +// qDebug("%d -> %d", oldPos, newPos); + return newPos; +} + +/*!/ Returns true if position \a pos is a valid cursor position. In a Unicode context some positions in the text are not valid @@ -815,16 +850,8 @@ QTextLine QTextLayout::lineAt(int i) const */ QTextLine QTextLayout::lineForTextPosition(int pos) const { - for (int i = 0; i < d->lines.size(); ++i) { - const QScriptLine& line = d->lines[i]; - if (line.from + (int)line.length > pos) - return QTextLine(i, d); - } - if (!d->layoutData) - d->itemize(); - if (pos == d->layoutData->string.length() && d->lines.size()) - return QTextLine(d->lines.size()-1, d); - return QTextLine(); + int lineNum = d->lineNumberForTextPosition(pos); + return lineNum >= 0 ? lineAt(lineNum) : QTextLine(); } /*! @@ -919,201 +946,6 @@ void QTextLayout::setFlags(int flags) } } -struct QTextLineItemIterator -{ - QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(), - const QTextLayout::FormatRange *_selection = 0); - - inline bool atEnd() const { return logicalItem >= nItems - 1; } - QScriptItem &next(); - - bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const; - inline bool isOutsideSelection() const { - QFixed tmp1, tmp2; - return !getSelectionBounds(&tmp1, &tmp2); - } - - QTextEngine *eng; - - QFixed x; - QFixed pos_x; - const QScriptLine &line; - QScriptItem *si; - - int lineEnd; - int firstItem; - int lastItem; - int nItems; - int logicalItem; - int item; - int itemLength; - - int glyphsStart; - int glyphsEnd; - int itemStart; - int itemEnd; - - QFixed itemWidth; - - QVarLengthArray visualOrder; - QVarLengthArray levels; - - const QTextLayout::FormatRange *selection; -}; - -QTextLineItemIterator::QTextLineItemIterator(QTextEngine *_eng, int lineNum, const QPointF &pos, - const QTextLayout::FormatRange *_selection) - : eng(_eng), - line(eng->lines[lineNum]), - si(0), - lineEnd(line.from + line.length), - firstItem(eng->findItem(line.from)), - lastItem(eng->findItem(lineEnd - 1)), - nItems((firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0), - logicalItem(-1), - item(-1), - visualOrder(nItems), - levels(nItems), - selection(_selection) -{ - pos_x = x = QFixed::fromReal(pos.x()); - - x += line.x; - - x += alignLine(eng, line); - - for (int i = 0; i < nItems; ++i) - levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel; - QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); - - eng->shapeLine(line); -} - -QScriptItem &QTextLineItemIterator::next() -{ - x += itemWidth; - - ++logicalItem; - item = visualOrder[logicalItem] + firstItem; - itemLength = eng->length(item); - si = &eng->layoutData->items[item]; - if (!si->num_glyphs) - eng->shape(item); - - if (si->analysis.flags >= QScriptAnalysis::TabOrObject) { - itemWidth = si->width; - return *si; - } - - unsigned short *logClusters = eng->logClusters(si); - QGlyphLayout glyphs = eng->shapedGlyphs(si); - - itemStart = qMax(line.from, si->position); - glyphsStart = logClusters[itemStart - si->position]; - if (lineEnd < si->position + itemLength) { - itemEnd = lineEnd; - glyphsEnd = logClusters[itemEnd-si->position]; - } else { - itemEnd = si->position + itemLength; - glyphsEnd = si->num_glyphs; - } - // show soft-hyphen at line-break - if (si->position + itemLength >= lineEnd - && eng->layoutData->string.at(lineEnd - 1) == 0x00ad) - glyphs.attributes[glyphsEnd - 1].dontPrint = false; - - itemWidth = 0; - for (int g = glyphsStart; g < glyphsEnd; ++g) - itemWidth += glyphs.effectiveAdvance(g); - - return *si; -} - -static QFixed offsetInLigature(const unsigned short *logClusters, - const QGlyphLayout &glyphs, - int pos, int max, int glyph_pos) -{ - int offsetInCluster = 0; - for (int i = pos - 1; i >= 0; i--) { - if (logClusters[i] == glyph_pos) - offsetInCluster++; - else - break; - } - - // in the case that the offset is inside a (multi-character) glyph, - // interpolate the position. - if (offsetInCluster > 0) { - int clusterLength = 0; - for (int i = pos - offsetInCluster; i < max; i++) { - if (logClusters[i] == glyph_pos) - clusterLength++; - else - break; - } - if (clusterLength) - return glyphs.advances_x[glyph_pos] * offsetInCluster / clusterLength; - } - - return 0; -} - -bool QTextLineItemIterator::getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const -{ - *selectionX = *selectionWidth = 0; - - if (!selection) - return false; - - if (si->analysis.flags >= QScriptAnalysis::TabOrObject) { - if (si->position >= selection->start + selection->length - || si->position + itemLength <= selection->start) - return false; - - *selectionX = x; - *selectionWidth = itemWidth; - } else { - unsigned short *logClusters = eng->logClusters(si); - QGlyphLayout glyphs = eng->shapedGlyphs(si); - - int from = qMax(itemStart, selection->start) - si->position; - int to = qMin(itemEnd, selection->start + selection->length) - si->position; - if (from >= to) - return false; - - int start_glyph = logClusters[from]; - int end_glyph = (to == eng->length(item)) ? si->num_glyphs : logClusters[to]; - QFixed soff; - QFixed swidth; - if (si->analysis.bidiLevel %2) { - for (int g = glyphsEnd - 1; g >= end_glyph; --g) - soff += glyphs.effectiveAdvance(g); - for (int g = end_glyph - 1; g >= start_glyph; --g) - swidth += glyphs.effectiveAdvance(g); - } else { - for (int g = glyphsStart; g < start_glyph; ++g) - soff += glyphs.effectiveAdvance(g); - for (int g = start_glyph; g < end_glyph; ++g) - swidth += glyphs.effectiveAdvance(g); - } - - // If the starting character is in the middle of a ligature, - // selection should only contain the right part of that ligature - // glyph, so we need to get the width of the left part here and - // add it to *selectionX - QFixed leftOffsetInLigature = offsetInLigature(logClusters, glyphs, from, - to, start_glyph); - *selectionX = x + soff + leftOffsetInLigature; - *selectionWidth = swidth - leftOffsetInLigature; - // If the ending character is also part of a ligature, swidth does - // not contain that part yet, we also need to find out the width of - // that left part - *selectionWidth += offsetInLigature(logClusters, glyphs, to, - eng->length(item), end_glyph); - } - return true; -} - static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPointF &pos, QTextLayout::FormatRange *selection, QPainterPath *region, QRectF boundingRect) { @@ -1382,18 +1214,9 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition QFixed pos_y = QFixed::fromReal(position.y()); cursorPosition = qBound(0, cursorPosition, d->layoutData->string.length()); - int line = 0; - if (cursorPosition == d->layoutData->string.length()) { - line = d->lines.size() - 1; - } else { - // ### binary search - for (line = 0; line < d->lines.size(); line++) { - const QScriptLine &sl = d->lines[line]; - if (sl.from <= cursorPosition && sl.from + (int)sl.length > cursorPosition) - break; - } - } - + int line = d->lineNumberForTextPosition(cursorPosition); + if (line < 0) + line = 0; if (line >= d->lines.size()) return; @@ -1402,7 +1225,15 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition qreal x = position.x() + l.cursorToX(cursorPosition); - int itm = d->findItem(cursorPosition - 1); + int itm; + + if (d->visualCursorMovement()) { + if (cursorPosition == sl.from + sl.length) + cursorPosition--; + itm = d->findItem(cursorPosition); + } else + itm = d->findItem(cursorPosition - 1); + QFixed base = sl.base(); QFixed descent = sl.descent; bool rightToLeft = d->isRightToLeft(); @@ -1512,7 +1343,7 @@ QRectF QTextLine::rect() const QRectF QTextLine::naturalTextRect() const { const QScriptLine& sl = eng->lines[i]; - QFixed x = sl.x + alignLine(eng, sl); + QFixed x = sl.x + eng->alignLine(sl); QFixed width = sl.textWidth; if (sl.justified) @@ -2632,9 +2463,10 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const eng->itemize(); const QScriptLine &line = eng->lines[i]; + bool lastLine = i >= eng->lines.size() - 1; QFixed x = line.x; - x += alignLine(eng, line); + x += eng->alignLine(line); if (!i && !eng->layoutData->items.size()) { *cursorPos = 0; @@ -2720,21 +2552,29 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const logClusters = eng->logClusters(si); glyphs = eng->shapedGlyphs(si); if (si->analysis.flags >= QScriptAnalysis::TabOrObject) { - if(pos == l) + if (pos == (reverse ? 0 : l)) x += si->width; } else { + bool rtl = eng->isRightToLeft(); + bool visual = eng->visualCursorMovement(); if (reverse) { int end = qMin(lineEnd, si->position + l) - si->position; int glyph_end = end == l ? si->num_glyphs : logClusters[end]; - for (int i = glyph_end - 1; i >= glyph_pos; i--) + int glyph_start = glyph_pos; + if (visual && !rtl && !(lastLine && itm == (visualOrder[nItems - 1] + firstItem))) + glyph_start++; + for (int i = glyph_end - 1; i >= glyph_start; i--) x += glyphs.effectiveAdvance(i); } else { int start = qMax(line.from - si->position, 0); int glyph_start = logClusters[start]; - for (int i = glyph_start; i < glyph_pos; i++) + int glyph_end = glyph_pos; + if (!visual || !rtl || (lastLine && itm == visualOrder[0] + firstItem)) + glyph_end--; + for (int i = glyph_start; i <= glyph_end; i++) x += glyphs.effectiveAdvance(i); } - x += offsetInLigature(logClusters, glyphs, pos, line.length, glyph_pos); + x += eng->offsetInLigature(si, pos, line.length, glyph_pos); } *cursorPos = pos + si->position; @@ -2753,6 +2593,8 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const { QFixed x = QFixed::fromReal(_x); const QScriptLine &line = eng->lines[i]; + bool lastLine = i >= eng->lines.size() - 1; + int lineNum = i; if (!eng->layoutData) eng->itemize(); @@ -2770,7 +2612,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const return 0; x -= line.x; - x -= alignLine(eng, line); + x -= eng->alignLine(line); // qDebug("xToCursor: x=%f, cpos=%d", x.toReal(), cpos); QVarLengthArray visualOrder(nItems); @@ -2779,6 +2621,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel; QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); + bool visual = eng->visualCursorMovement(); if (x <= 0) { // left of first item int item = visualOrder[0]+firstItem; @@ -2795,8 +2638,13 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const || (line.justified && x < line.width)) { // has to be in one of the runs QFixed pos; + bool rtl = eng->isRightToLeft(); eng->shapeLine(line); + QVector insertionPoints; + if (visual && rtl) + eng->insertionPointsForLine(lineNum, insertionPoints); + int nchars = 0; for (int i = 0; i < nItems; ++i) { int item = visualOrder[i]+firstItem; QScriptItem &si = eng->layoutData->items[item]; @@ -2826,6 +2674,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const if (pos + item_width < x) { pos += item_width; + nchars += end; continue; } // qDebug(" inside run"); @@ -2870,27 +2719,60 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const } else { QFixed dist = INT_MAX/256; if (si.analysis.bidiLevel % 2) { - pos += item_width; - while (gs <= ge) { - if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { - glyph_pos = gs; - dist = qAbs(x-pos); + if (!visual || rtl || (lastLine && i == nItems - 1)) { + pos += item_width; + while (gs <= ge) { + if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { + glyph_pos = gs; + dist = qAbs(x-pos); + } + pos -= glyphs.effectiveAdvance(gs); + ++gs; + } + } else { + while (ge >= gs) { + if (glyphs.attributes[ge].clusterStart && qAbs(x-pos) < dist) { + glyph_pos = ge; + dist = qAbs(x-pos); + } + pos += glyphs.effectiveAdvance(ge); + --ge; } - pos -= glyphs.effectiveAdvance(gs); - ++gs; } } else { - while (gs <= ge) { - if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { - glyph_pos = gs; - dist = qAbs(x-pos); + if (!visual || !rtl || (lastLine && i == 0)) { + while (gs <= ge) { + if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { + glyph_pos = gs; + dist = qAbs(x-pos); + } + pos += glyphs.effectiveAdvance(gs); + ++gs; } - pos += glyphs.effectiveAdvance(gs); - ++gs; + } else { + QFixed oldPos = pos; + while (gs <= ge) { + pos += glyphs.effectiveAdvance(gs); + if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) { + glyph_pos = gs; + dist = qAbs(x-pos); + } + ++gs; + } + pos = oldPos; } } - if (qAbs(x-pos) < dist) + if (qAbs(x-pos) < dist) { + if (visual) { + if (!rtl && i < nItems - 1) { + nchars += end; + continue; + } + if (rtl && nchars > 0) + return insertionPoints[lastLine ? nchars : nchars - 1]; + } return si.position + end; + } } Q_ASSERT(glyph_pos != -1); int j; diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h index 9dd8ebd..6aa81f9 100644 --- a/src/gui/text/qtextlayout.h +++ b/src/gui/text/qtextlayout.h @@ -50,6 +50,7 @@ #include #include #include +#include QT_BEGIN_HEADER @@ -136,6 +137,9 @@ public: void setCacheEnabled(bool enable); bool cacheEnabled() const; + void setCursorMoveStyle(QTextCursor::MoveStyle style); + QTextCursor::MoveStyle cursorMoveStyle() const; + void beginLayout(); void endLayout(); void clearLayout(); @@ -153,6 +157,8 @@ public: bool isValidCursorPosition(int pos) const; int nextCursorPosition(int oldPos, CursorMode mode = SkipCharacters) const; int previousCursorPosition(int oldPos, CursorMode mode = SkipCharacters) const; + int leftCursorPosition(int oldPos) const; + int rightCursorPosition(int oldPos) const; void draw(QPainter *p, const QPointF &pos, const QVector &selections = QVector(), const QRectF &clip = QRectF()) const; diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 3eac64a..a1b3ff8 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -1577,6 +1577,7 @@ void QLineControl::processKeyEvent(QKeyEvent* event) } bool unknown = false; + bool visual = cursorMoveStyle() == QTextCursor::Visual; if (false) { } @@ -1641,11 +1642,11 @@ void QLineControl::processKeyEvent(QKeyEvent* event) #endif moveCursor(selectionEnd(), false); } else { - cursorForward(0, layoutDirection() == Qt::LeftToRight ? 1 : -1); + cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1)); } } else if (event == QKeySequence::SelectNextChar) { - cursorForward(1, layoutDirection() == Qt::LeftToRight ? 1 : -1); + cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1)); } else if (event == QKeySequence::MoveToPreviousChar) { #if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER) @@ -1656,11 +1657,11 @@ void QLineControl::processKeyEvent(QKeyEvent* event) #endif moveCursor(selectionStart(), false); } else { - cursorForward(0, layoutDirection() == Qt::LeftToRight ? -1 : 1); + cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1)); } } else if (event == QKeySequence::SelectPreviousChar) { - cursorForward(1, layoutDirection() == Qt::LeftToRight ? -1 : 1); + cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1)); } else if (event == QKeySequence::MoveToNextWord) { if (echoMode() == QLineEdit::Normal) diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index 3c505c8..0042f17 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -160,6 +160,8 @@ public: int cursorWidth() const { return m_cursorWidth; } void setCursorWidth(int value) { m_cursorWidth = value; } + QTextCursor::MoveStyle cursorMoveStyle() const { return m_textLayout.cursorMoveStyle(); } + void setCursorMoveStyle(QTextCursor::MoveStyle style) { m_textLayout.setCursorMoveStyle(style); } void moveCursor(int pos, bool mark = false); void cursorForward(bool mark, int steps) @@ -167,10 +169,12 @@ public: int c = m_cursor; if (steps > 0) { while (steps--) - c = m_textLayout.nextCursorPosition(c); + c = cursorMoveStyle() == QTextCursor::Visual ? m_textLayout.rightCursorPosition(c) + : m_textLayout.nextCursorPosition(c); } else if (steps < 0) { while (steps++) - c = m_textLayout.previousCursorPosition(c); + c = cursorMoveStyle() == QTextCursor::Visual ? m_textLayout.leftCursorPosition(c) + : m_textLayout.previousCursorPosition(c); } moveCursor(c, mark); } diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index 07bd273..43c3f52 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -1112,6 +1112,34 @@ void QLineEdit::setDragEnabled(bool b) /*! + \property QLineEdit::cursorMoveStyle + \brief the movement style of cursor in this line edit + \since 4.8 + + When this property is set to QTextCursor::Visual, the line edit will use visual + movement style. Pressing the left arrow key will always cause the cursor to move + left, regardless of the text's writing direction. The same behavior applies to + right arrow key. + + When the property is QTextCursor::Logical (the default), within a LTR text block, + increase cursor position when pressing left arrow key, decrease cursor position + when pressing the right arrow key. If the text block is right to left, the opposite + behavior applies. +*/ + +QTextCursor::MoveStyle QLineEdit::cursorMoveStyle() const +{ + Q_D(const QLineEdit); + return d->control->cursorMoveStyle(); +} + +void QLineEdit::setCursorMoveStyle(QTextCursor::MoveStyle style) +{ + Q_D(QLineEdit); + d->control->setCursorMoveStyle(style); +} + +/*! \property QLineEdit::acceptableInput \brief whether the input satisfies the inputMask and the validator. diff --git a/src/gui/widgets/qlineedit.h b/src/gui/widgets/qlineedit.h index 636cee7..73a736c 100644 --- a/src/gui/widgets/qlineedit.h +++ b/src/gui/widgets/qlineedit.h @@ -43,6 +43,7 @@ #define QLINEEDIT_H #include +#include #include #include @@ -158,6 +159,9 @@ public: void setDragEnabled(bool b); bool dragEnabled() const; + void setCursorMoveStyle(QTextCursor::MoveStyle style); + QTextCursor::MoveStyle cursorMoveStyle() const; + QString inputMask() const; void setInputMask(const QString &inputMask); bool hasAcceptableInput() const; diff --git a/tests/auto/qcomplextext/tst_qcomplextext.cpp b/tests/auto/qcomplextext/tst_qcomplextext.cpp index 3d8e290..04943c5 100644 --- a/tests/auto/qcomplextext/tst_qcomplextext.cpp +++ b/tests/auto/qcomplextext/tst_qcomplextext.cpp @@ -71,6 +71,10 @@ private slots: void bidiReorderString(); void bidiCursor_qtbug2795(); void bidiCursor_PDF(); + void bidiCursorMovement_data(); + void bidiCursorMovement(); + void bidiCursorLogicalMovement_data(); + void bidiCursorLogicalMovement(); }; tst_QComplexText::tst_QComplexText() @@ -185,6 +189,89 @@ void tst_QComplexText::bidiCursor_qtbug2795() QVERIFY(x1 == x2); } +void tst_QComplexText::bidiCursorMovement_data() +{ + QTest::addColumn("logical"); + QTest::addColumn("basicDir"); + + const LV *data = logical_visual; + while ( data->name ) { + //next we fill it with data + QTest::newRow( data->name ) + << QString::fromUtf8( data->logical ) + << (int) data->basicDir; + data++; + } +} + +void tst_QComplexText::bidiCursorMovement() +{ + QFETCH(QString, logical); + QFETCH(int, basicDir); + + QTextLayout layout(logical); + + QTextOption option = layout.textOption(); + option.setTextDirection(basicDir == QChar::DirL ? Qt::LeftToRight : Qt::RightToLeft); + layout.setTextOption(option); + bool moved; + int oldPos, newPos = 0; + qreal x, newX; + + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + + newX = line.cursorToX(0); + do { + oldPos = newPos; + x = newX; + newX = line.cursorToX(oldPos); + if (basicDir == QChar::DirL) { + QVERIFY(newX >= x); + newPos = layout.rightCursorPosition(oldPos); + } else + { + QVERIFY(newX <= x); + newPos = layout.leftCursorPosition(oldPos); + } + moved = (oldPos != newPos); + } while (moved); +} + +void tst_QComplexText::bidiCursorLogicalMovement_data() +{ + bidiCursorMovement_data(); +} + +void tst_QComplexText::bidiCursorLogicalMovement() +{ + QFETCH(QString, logical); + QFETCH(int, basicDir); + + QTextLayout layout(logical); + + QTextOption option = layout.textOption(); + option.setTextDirection(basicDir == QChar::DirL ? Qt::LeftToRight : Qt::RightToLeft); + layout.setTextOption(option); + bool moved; + int oldPos, newPos = 0; + + do { + oldPos = newPos; + newPos = layout.nextCursorPosition(oldPos); + QVERIFY(newPos >= oldPos); + moved = (oldPos != newPos); + } while (moved); + + do { + oldPos = newPos; + newPos = layout.previousCursorPosition(oldPos); + QVERIFY(newPos <= oldPos); + moved = (oldPos != newPos); + } while (moved); +} + void tst_QComplexText::bidiCursor_PDF() { QString str = QString::fromUtf8("\342\200\252hello\342\200\254"); diff --git a/tests/auto/qlineedit/tst_qlineedit.cpp b/tests/auto/qlineedit/tst_qlineedit.cpp index 9176174..f45481c 100644 --- a/tests/auto/qlineedit/tst_qlineedit.cpp +++ b/tests/auto/qlineedit/tst_qlineedit.cpp @@ -282,6 +282,12 @@ private slots: void validateAndSet(); #endif + void bidiVisualMovement_data(); + void bidiVisualMovement(); + + void bidiLogicalMovement_data(); + void bidiLogicalMovement(); + protected slots: #ifdef QT3_SUPPORT void lostFocus(); @@ -3760,5 +3766,135 @@ void tst_QLineEdit::QTBUG13520_textNotVisible() } +void tst_QLineEdit::bidiVisualMovement_data() +{ + QTest::addColumn("logical"); + QTest::addColumn("basicDir"); + QTest::addColumn("positionList"); + + QTest::newRow("Latin text") + << QString::fromUtf8("abc") + << (int) QChar::DirL + << (IntList() << 0 << 1 << 2 << 3); + QTest::newRow("Hebrew text, one item") + << QString::fromUtf8("\327\220\327\221\327\222") + << (int) QChar::DirR + << (QList() << 0 << 1 << 2 << 3); + QTest::newRow("Hebrew text after Latin text") + << QString::fromUtf8("abc\327\220\327\221\327\222") + << (int) QChar::DirL + << (QList() << 0 << 1 << 2 << 6 << 5 << 4 << 3); + QTest::newRow("Latin text after Hebrew text") + << QString::fromUtf8("\327\220\327\221\327\222abc") + << (int) QChar::DirR + << (QList() << 0 << 1 << 2 << 6 << 5 << 4 << 3); + QTest::newRow("LTR, 3 items") + << QString::fromUtf8("abc\327\220\327\221\327\222abc") + << (int) QChar::DirL + << (QList() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 9); + QTest::newRow("RTL, 3 items") + << QString::fromUtf8("\327\220\327\221\327\222abc\327\220\327\221\327\222") + << (int) QChar::DirR + << (QList() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 9); + QTest::newRow("LTR, 4 items") + << QString::fromUtf8("abc\327\220\327\221\327\222abc\327\220\327\221\327\222") + << (int) QChar::DirL + << (QList() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 12 << 11 << 10 << 9); + QTest::newRow("RTL, 4 items") + << QString::fromUtf8("\327\220\327\221\327\222abc\327\220\327\221\327\222abc") + << (int) QChar::DirR + << (QList() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 12 << 11 << 10 << 9); +} + +void tst_QLineEdit::bidiVisualMovement() +{ + QFETCH(QString, logical); + QFETCH(int, basicDir); + QFETCH(IntList, positionList); + + QLineEdit le; + le.setText(logical); + + le.setCursorMoveStyle(QTextCursor::Visual); + le.setCursorPosition(0); + + bool moved; + int i = 0, oldPos, newPos = 0; + + do { + oldPos = newPos; + QVERIFY(oldPos == positionList[i]); + if (basicDir == QChar::DirL) { + QTest::keyClick(&le, Qt::Key_Right); + } else + QTest::keyClick(&le, Qt::Key_Left); + newPos = le.cursorPosition(); + moved = (oldPos != newPos); + i++; + } while (moved); + + QVERIFY(i == positionList.size()); + + do { + i--; + oldPos = newPos; + QVERIFY(oldPos == positionList[i]); + if (basicDir == QChar::DirL) { + QTest::keyClick(&le, Qt::Key_Left); + } else + { + QTest::keyClick(&le, Qt::Key_Right); + } + newPos = le.cursorPosition(); + moved = (oldPos != newPos); + } while (moved && i >= 0); +} + +void tst_QLineEdit::bidiLogicalMovement_data() +{ + bidiVisualMovement_data(); +} + +void tst_QLineEdit::bidiLogicalMovement() +{ + QFETCH(QString, logical); + QFETCH(int, basicDir); + + QLineEdit le; + le.setText(logical); + + le.setCursorMoveStyle(QTextCursor::Logical); + le.setCursorPosition(0); + + bool moved; + int i = 0, oldPos, newPos = 0; + + do { + oldPos = newPos; + QVERIFY(oldPos == i); + if (basicDir == QChar::DirL) { + QTest::keyClick(&le, Qt::Key_Right); + } else + QTest::keyClick(&le, Qt::Key_Left); + newPos = le.cursorPosition(); + moved = (oldPos != newPos); + i++; + } while (moved); + + do { + i--; + oldPos = newPos; + QVERIFY(oldPos == i); + if (basicDir == QChar::DirL) { + QTest::keyClick(&le, Qt::Key_Left); + } else + { + QTest::keyClick(&le, Qt::Key_Right); + } + newPos = le.cursorPosition(); + moved = (oldPos != newPos); + } while (moved && i >= 0); +} + QTEST_MAIN(tst_QLineEdit) #include "tst_qlineedit.moc" diff --git a/tests/auto/qtextedit/tst_qtextedit.cpp b/tests/auto/qtextedit/tst_qtextedit.cpp index 9ca17b9..5a64593 100644 --- a/tests/auto/qtextedit/tst_qtextedit.cpp +++ b/tests/auto/qtextedit/tst_qtextedit.cpp @@ -42,7 +42,6 @@ #include - #include #include #include @@ -69,6 +68,7 @@ typedef QList pairListType; Q_DECLARE_METATYPE(pairListType); Q_DECLARE_METATYPE(keyPairType); Q_DECLARE_METATYPE(QList); +Q_DECLARE_METATYPE(QList); #ifdef Q_WS_MAC #include @@ -205,6 +205,11 @@ private slots: #ifndef QT_NO_CONTEXTMENU void taskQTBUG_7902_contextMenuCrash(); #endif + void bidiVisualMovement_data(); + void bidiVisualMovement(); + + void bidiLogicalMovement_data(); + void bidiLogicalMovement(); private: void createSelection(); @@ -2235,5 +2240,147 @@ void tst_QTextEdit::taskQTBUG_7902_contextMenuCrash() } #endif +void tst_QTextEdit::bidiVisualMovement_data() +{ + QTest::addColumn("logical"); + QTest::addColumn("basicDir"); + QTest::addColumn >("positionList"); + + QTest::newRow("Latin text") + << QString::fromUtf8("abc") + << (int) QChar::DirL + << (QList() << 0 << 1 << 2 << 3); + QTest::newRow("Hebrew text, one item") + << QString::fromUtf8("\327\220\327\221\327\222") + << (int) QChar::DirR + << (QList() << 0 << 1 << 2 << 3); + QTest::newRow("Hebrew text after Latin text") + << QString::fromUtf8("abc\327\220\327\221\327\222") + << (int) QChar::DirL + << (QList() << 0 << 1 << 2 << 6 << 5 << 4 << 3); + QTest::newRow("Latin text after Hebrew text") + << QString::fromUtf8("\327\220\327\221\327\222abc") + << (int) QChar::DirR + << (QList() << 0 << 1 << 2 << 6 << 5 << 4 << 3); + QTest::newRow("LTR, 3 items") + << QString::fromUtf8("abc\327\220\327\221\327\222abc") + << (int) QChar::DirL + << (QList() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 9); + QTest::newRow("RTL, 3 items") + << QString::fromUtf8("\327\220\327\221\327\222abc\327\220\327\221\327\222") + << (int) QChar::DirR + << (QList() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 9); + QTest::newRow("LTR, 4 items") + << QString::fromUtf8("abc\327\220\327\221\327\222abc\327\220\327\221\327\222") + << (int) QChar::DirL + << (QList() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 12 << 11 << 10 << 9); + QTest::newRow("RTL, 4 items") + << QString::fromUtf8("\327\220\327\221\327\222abc\327\220\327\221\327\222abc") + << (int) QChar::DirR + << (QList() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 12 << 11 << 10 << 9); +} + +void tst_QTextEdit::bidiVisualMovement() +{ + QFETCH(QString, logical); + QFETCH(int, basicDir); + QFETCH(QList, positionList); + + ed->setText(logical); + + QTextOption option = ed->document()->defaultTextOption(); + option.setTextDirection(basicDir == QChar::DirL ? Qt::LeftToRight : Qt::RightToLeft); + ed->document()->setDefaultTextOption(option); + + ed->document()->setDefaultCursorMoveStyle(QTextCursor::Visual); + ed->moveCursor(QTextCursor::Start); + ed->show(); + + bool moved; + int i = 0, oldPos, newPos = 0; + + do { + oldPos = newPos; + QVERIFY(oldPos == positionList[i]); + if (basicDir == QChar::DirL) { + ed->moveCursor(QTextCursor::Right); + } else + { + ed->moveCursor(QTextCursor::Left); + } + newPos = ed->textCursor().position(); + moved = (oldPos != newPos); + i++; + } while (moved); + + QVERIFY(i == positionList.size()); + + do { + i--; + oldPos = newPos; + QVERIFY(oldPos == positionList[i]); + if (basicDir == QChar::DirL) { + ed->moveCursor(QTextCursor::Left); + } else + { + ed->moveCursor(QTextCursor::Right); + } + newPos = ed->textCursor().position(); + moved = (oldPos != newPos); + } while (moved && i >= 0); +} + +void tst_QTextEdit::bidiLogicalMovement_data() +{ + bidiVisualMovement_data(); +} + +void tst_QTextEdit::bidiLogicalMovement() +{ + QFETCH(QString, logical); + QFETCH(int, basicDir); + + ed->setText(logical); + + QTextOption option = ed->document()->defaultTextOption(); + option.setTextDirection(basicDir == QChar::DirL ? Qt::LeftToRight : Qt::RightToLeft); + ed->document()->setDefaultTextOption(option); + + ed->document()->setDefaultCursorMoveStyle(QTextCursor::Logical); + ed->moveCursor(QTextCursor::Start); + ed->show(); + + bool moved; + int i = 0, oldPos, newPos = 0; + + do { + oldPos = newPos; + QVERIFY(oldPos == i); + if (basicDir == QChar::DirL) { + ed->moveCursor(QTextCursor::Right); + } else + { + ed->moveCursor(QTextCursor::Left); + } + newPos = ed->textCursor().position(); + moved = (oldPos != newPos); + i++; + } while (moved); + + do { + i--; + oldPos = newPos; + QVERIFY(oldPos == i); + if (basicDir == QChar::DirL) { + ed->moveCursor(QTextCursor::Left); + } else + { + ed->moveCursor(QTextCursor::Right); + } + newPos = ed->textCursor().position(); + moved = (oldPos != newPos); + } while (moved && i >= 0); +} + QTEST_MAIN(tst_QTextEdit) #include "tst_qtextedit.moc" -- cgit v0.12 From 4b264b241067ed58f8a72fc7b221565112d936f4 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Mon, 18 Apr 2011 17:08:30 +0200 Subject: Turn on HarfBuzz support for Mac/Cocoa It's possible to enable HarfBuzz text layout on Mac by either: - Set QT_ENABLE_HARFBUZZ environment variable when running a Qt app. - configure with -harfbuzz to build Qt, then HarfBuzz support will be turned on by default. HarfBuzz will only be used when the font explicitly requested is supported by HarfBuzz (aka. TrueType/OpenType font), other fonts (AAT fonts) will still be handled by Core Text. Using HarfBuzz for text layout will hopefully solve most tricky complex text shaping bugs on Mac. Task-number: QTBUG-17728 Reviewed-by: Eskil --- configure | 16 +++++++++++++++- src/gui/text/qtextengine.cpp | 34 +++++++++++++++++++++++++++++++++- src/gui/text/text.pri | 3 +++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 99b79fc..9b923ab 100755 --- a/configure +++ b/configure @@ -804,6 +804,7 @@ CFG_MAC_XARCH=auto CFG_MAC_CARBON=no CFG_MAC_COCOA=yes COMMANDLINE_MAC_CARBON=no +CFG_MAC_HARFBUZZ=no CFG_SXE=no CFG_PREFIX_INSTALL=yes CFG_SDK= @@ -1040,7 +1041,7 @@ while [ "$#" -gt 0 ]; do VAL=no ;; #Qt style yes options - -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-carbon|-universal|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-audio-backend|-svg|-declarative|-declarative-debug|-javascript-jit|-script|-scripttools|-rpath|-force-pkg-config|-s60|-usedeffiles) + -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-carbon|-universal|-harfbuzz|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-audio-backend|-svg|-declarative|-declarative-debug|-javascript-jit|-script|-scripttools|-rpath|-force-pkg-config|-s60|-usedeffiles) VAR=`echo $1 | sed "s,^-\(.*\),\1,"` VAL=yes ;; @@ -1498,6 +1499,13 @@ while [ "$#" -gt 0 ]; do UNKNOWN_OPT=yes fi ;; + harfbuzz) + if [ "$PLATFORM_MAC" = "yes" ] && [ "$CFG_MAC_CARBON" != "yes" ] && [ "$VAL" = "yes" ]; then + CFG_MAC_HARFBUZZ="$VAL" + else + UNKNOWN_OPT=yes + fi + ;; framework) if [ "$PLATFORM_MAC" = "yes" ] || [ "$PLATFORM_QPA" = "yes" ]; then @@ -4245,6 +4253,11 @@ Qt/Mac only: -sdk ......... Build Qt using Apple provided SDK . This option requires gcc 4. To use a different SDK with gcc 3.3, set the SDKROOT environment variable. + -harfbuzz .......... Use HarfBuzz to do text layout instead of Core Text when possible. + It is only available to Cocoa builds. + * -no-harfbuzz ....... Disable HarfBuzz on Mac. It can still be enabled by setting + QT_ENABLE_HARFBUZZ environment variable. + EOF fi @@ -7209,6 +7222,7 @@ fi [ "$CFG_NAS" = "system" ] && QT_CONFIG="$QT_CONFIG nas" [ "$CFG_OPENSSL" = "yes" ] && QT_CONFIG="$QT_CONFIG openssl" [ "$CFG_OPENSSL" = "linked" ] && QT_CONFIG="$QT_CONFIG openssl-linked" +[ "$CFG_MAC_HARFBUZZ" = "yes" ] && QT_CONFIG="$QT_CONFIG harfbuzz" if [ "$PLATFORM_X11" = "yes" ]; then [ "$CFG_SM" = "yes" ] && QT_CONFIG="$QT_CONFIG x11sm" diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 0e649f0..dab4bb7 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -856,6 +856,21 @@ void QTextEngine::shapeLine(const QScriptLine &line) } } +#if !defined(QT_ENABLE_HARFBUZZ_FOR_MAC) +static bool enableHarfBuzz() +{ + static enum { Yes, No, Unknown } status = Unknown; + + if (status == Unknown) { + QByteArray v = qgetenv("QT_ENABLE_HARFBUZZ"); + bool value = !v.isEmpty() && v != "0" && v != "false"; + if (value) status = Yes; + else status = No; + } + return status == Yes; +} +#endif + void QTextEngine::shapeText(int item) const { Q_ASSERT(item < layoutData->items.size()); @@ -865,7 +880,24 @@ void QTextEngine::shapeText(int item) const return; #if defined(Q_WS_MAC) - shapeTextMac(item); +#if !defined(QT_ENABLE_HARFBUZZ_FOR_MAC) + if (enableHarfBuzz()) { +#endif + QFontEngine *actualFontEngine = fontEngine(si, &si.ascent, &si.descent, &si.leading); + if (actualFontEngine->type() == QFontEngine::Multi) + actualFontEngine = static_cast(actualFontEngine)->engine(0); + + HB_Face face = actualFontEngine->harfbuzzFace(); + HB_Script script = (HB_Script) si.analysis.script; + if (face->supported_scripts[script]) + shapeTextWithHarfbuzz(item); + else + shapeTextMac(item); +#if !defined(QT_ENABLE_HARFBUZZ_FOR_MAC) + } else { + shapeTextMac(item); + } +#endif #elif defined(Q_WS_WINCE) shapeTextWithCE(item); #else diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index df9398c..83be5b4 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -114,6 +114,9 @@ unix:x11 { OBJECTIVE_SOURCES += \ text/qfontengine_coretext.mm \ text/qfontengine_mac.mm + contains(QT_CONFIG, harfbuzz) { + DEFINES += QT_ENABLE_HARFBUZZ_FOR_MAC + } } embedded { -- cgit v0.12 From 8c68e8ffa32ca26d0fd87f1349d6783e4242a9d1 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Thu, 24 Mar 2011 13:33:31 +0100 Subject: Let QTextLine decide its own x position in QPainter So that it can take trailing space width into account when doing right aligned text drawing. Backported from master. Task-number: QTBUG-18303 Reviewed-by: Eskil --- src/gui/painting/qpainter.cpp | 12 ++++++++---- src/gui/text/qtextengine.cpp | 16 ++++++++++++++++ src/gui/text/qtextengine_p.h | 1 + src/gui/text/qtextlayout.cpp | 19 +------------------ 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 0e279c9..3735e7c 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -8097,12 +8097,16 @@ start_lengthVariant: QTextLine line = textLayout.lineAt(i); qreal advance = line.horizontalAdvance(); - if (tf & Qt::AlignRight) - xoff = r.width() - advance; + xoff = 0; + if (tf & Qt::AlignRight) { + QTextEngine *eng = textLayout.engine(); + xoff = r.width() - advance - + eng->leadingSpaceWidth(eng->lines[line.lineNumber()]).toReal(); + } else if (tf & Qt::AlignHCenter) - xoff = (r.width() - advance)/2; + xoff = (r.width() - advance) / 2; - line.draw(painter, QPointF(r.x() + xoff + line.x(), r.y() + yoff)); + line.draw(painter, QPointF(r.x() + xoff, r.y() + yoff)); } if (restore) { diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 4378c62..4f86cff 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2681,6 +2681,22 @@ void QTextEngine::resolveAdditionalFormats() const specialData->resolvedFormatIndices = indices; } +QFixed QTextEngine::leadingSpaceWidth(const QScriptLine &line) +{ + if (!line.hasTrailingSpaces + || (option.flags() & QTextOption::IncludeTrailingSpaces) + || !isRightToLeft()) + return QFixed(); + + int pos = line.length; + const HB_CharAttributes *attributes = this->attributes(); + if (!attributes) + return QFixed(); + while (pos > 0 && attributes[line.from + pos - 1].whiteSpace) + --pos; + return width(line.from + pos, line.length - pos); +} + QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f) : QTextEngine(string, f), _layoutData(string, _memory, MemSize) diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 34723ab..67d7453 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -592,6 +592,7 @@ public: QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0) const; void shapeLine(const QScriptLine &line); + QFixed leadingSpaceWidth(const QScriptLine &line); private: void setBoundary(int strPos) const; diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 905f81b..692620f 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -64,23 +64,6 @@ QT_BEGIN_NAMESPACE #define SuppressText 0x5012 #define SuppressBackground 0x513 -static inline QFixed leadingSpaceWidth(QTextEngine *eng, const QScriptLine &line) -{ - if (!line.hasTrailingSpaces - || (eng->option.flags() & QTextOption::IncludeTrailingSpaces) - || !(eng->option.alignment() & Qt::AlignRight) - || !eng->isRightToLeft()) - return QFixed(); - - int pos = line.length; - const HB_CharAttributes *attributes = eng->attributes(); - if (!attributes) - return QFixed(); - while (pos > 0 && attributes[line.from + pos - 1].whiteSpace) - --pos; - return eng->width(line.from + pos, line.length - pos); -} - static QFixed alignLine(QTextEngine *eng, const QScriptLine &line) { QFixed x = 0; @@ -91,7 +74,7 @@ static QFixed alignLine(QTextEngine *eng, const QScriptLine &line) if (align & Qt::AlignJustify && eng->isRightToLeft()) align = Qt::AlignRight; if (align & Qt::AlignRight) - x = line.width - (line.textAdvance + leadingSpaceWidth(eng, line)); + x = line.width - (line.textAdvance + eng->leadingSpaceWidth(line)); else if (align & Qt::AlignHCenter) x = (line.width - line.textAdvance)/2; } -- cgit v0.12 From 0201d5f5a8c95bd4f6b94726ed0db2b83cd3efc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Tue, 19 Apr 2011 11:45:29 +0200 Subject: Skip linearGradientSymmetry test on QWS. QWS defines GRADIENT_STOPTABLE_SIZE to be 256, which is not enough resolution for this test to pass. Reviewed-by: Eskil Abrahamsen Blomfeldt --- tests/auto/qpainter/tst_qpainter.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/auto/qpainter/tst_qpainter.cpp b/tests/auto/qpainter/tst_qpainter.cpp index 64dacec..76bc5d63 100644 --- a/tests/auto/qpainter/tst_qpainter.cpp +++ b/tests/auto/qpainter/tst_qpainter.cpp @@ -4016,6 +4016,9 @@ void tst_QPainter::linearGradientSymmetry_data() void tst_QPainter::linearGradientSymmetry() { +#ifdef Q_WS_QWS + QSKIP("QWS has limited resolution in the gradient color table", SkipAll); +#else QFETCH(QGradientStops, stops); QImage a(64, 8, QImage::Format_ARGB32_Premultiplied); @@ -4037,6 +4040,7 @@ void tst_QPainter::linearGradientSymmetry() b = b.mirrored(true); QCOMPARE(a, b); +#endif } void tst_QPainter::gradientInterpolation() -- cgit v0.12 From b86c9120710bf1481df5f6541618169a82fd65b8 Mon Sep 17 00:00:00 2001 From: Jiang Jiang Date: Tue, 19 Apr 2011 12:48:19 +0200 Subject: Don't transform glyph positions for Core Graphics paint engine Since it already transformed text positions based on transform matrix on QPainter. Reviewed-by: Eskil --- src/gui/painting/qpainter.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index cbd16ae..25bf6be 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -156,7 +156,8 @@ static bool qt_paintengine_supports_transformations(QPaintEngine::Type type) { return type == QPaintEngine::OpenGL2 || type == QPaintEngine::OpenVG - || type == QPaintEngine::OpenGL; + || type == QPaintEngine::OpenGL + || type == QPaintEngine::CoreGraphics; } #ifndef QT_NO_DEBUG @@ -5817,7 +5818,7 @@ void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs) bool paintEngineSupportsTransformations = d->extended != 0 ? qt_paintengine_supports_transformations(d->extended->type()) - : false; + : qt_paintengine_supports_transformations(d->engine->type()); for (int i=0; i Date: Tue, 19 Apr 2011 15:19:31 +0200 Subject: Fix compilation with Qt3Support Reviewed-by: Fabien Freling --- src/qt3support/text/q3richtext.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt3support/text/q3richtext.cpp b/src/qt3support/text/q3richtext.cpp index 668a322..6c77405 100644 --- a/src/qt3support/text/q3richtext.cpp +++ b/src/qt3support/text/q3richtext.cpp @@ -63,6 +63,7 @@ #include "qstyleoption.h" #include "q3stylesheet.h" #include "qtextstream.h" +#include #include #include -- cgit v0.12 From 364ce5b7f5379499562b4f4f5a68da7ba068fe1e Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Tue, 19 Apr 2011 15:47:23 +0200 Subject: Fixed a crash on Windows XP with mingw in threaded-code The thread callback doesn't align the stack on 16-bytes on WinXP. That causes a crash when we call SSE code. So now we tell the compiler to force that alignment of the stack. Task: QTBUG-18631 Reviewed-By: Olivier --- src/corelib/thread/qthread_win.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 6b7932b..44e8958 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -288,7 +288,7 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data) #ifndef QT_NO_THREAD -unsigned int __stdcall QThreadPrivate::start(void *arg) +unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(void *arg) { QThread *thr = reinterpret_cast(arg); QThreadData *data = QThreadData::get2(thr); -- cgit v0.12 From 62d0923a822a5a0f1466fa36ac24e96472d1a6d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 19 Apr 2011 07:57:39 -0400 Subject: wayland: Add native access interface for Wayland plugin --- .../platforms/wayla