diff options
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 2 | ||||
-rw-r--r-- | src/quick/items/qquickitem.cpp | 30 | ||||
-rw-r--r-- | src/quick/items/qquickitem.h | 3 | ||||
-rw-r--r-- | src/quick/items/qquicktext.cpp | 19 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 39 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 3 | ||||
-rw-r--r-- | src/quick/quick.pro | 2 | ||||
-rw-r--r-- | tests/auto/qml/qjsengine/tst_qjsengine.cpp | 26 | ||||
-rw-r--r-- | tests/auto/quick/qquickitem2/data/qtbug_50516_2_1.qml | 13 | ||||
-rw-r--r-- | tests/auto/quick/qquickitem2/data/qtbug_50516_2_2.qml | 12 | ||||
-rw-r--r-- | tests/auto/quick/qquickitem2/data/qtbug_50516_2_3.qml | 16 | ||||
-rw-r--r-- | tests/auto/quick/qquickitem2/data/qtbug_50516_2_4.qml | 15 | ||||
-rw-r--r-- | tests/auto/quick/qquickitem2/data/qtbug_50516_2_5.qml | 16 | ||||
-rw-r--r-- | tests/auto/quick/qquickitem2/data/qtbug_50516_2_6.qml | 17 | ||||
-rw-r--r-- | tests/auto/quick/qquickitem2/tst_qquickitem.cpp | 64 |
16 files changed, 268 insertions, 10 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 8f471132b7..bcd97efee8 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -330,6 +330,8 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje } else if (property->isV4Function()) { Scope scope(engine); ScopedContext global(scope, engine->qmlContext()); + if (!global) + global = engine->rootContext(); return QV4::QObjectMethod::create(global, object, property->coreIndex); } else if (property->isSignalHandler()) { QmlSignalHandler::initProto(engine); diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index b603e1a58f..24e52ff65e 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2068,6 +2068,10 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus) \value ItemRotationHasChanged The item's rotation has changed. ItemChangeData::realValue contains the new rotation. + + \value ItemDevicePixelRatioHasChanged The device pixel ratio of the screen + the item is on has changed. ItemChangedData::realValue contains the new + device pixel ratio. */ /*! @@ -2471,6 +2475,7 @@ QQuickItem *QQuickItemPrivate::prevTabChildItem(const QQuickItem *item, int star QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, bool forward) { Q_ASSERT(item); + qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: item:" << item << ", forward:" << forward; if (!item->window()) return item; @@ -2481,19 +2486,25 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo bool all = QGuiApplication::styleHints()->tabFocusBehavior() == Qt::TabFocusAllControls; QQuickItem *from = 0; + bool isTabFence = item->d_func()->isTabFence; if (forward) { - from = item->parentItem(); + if (!isTabFence) + from = item->parentItem(); } else { if (!item->childItems().isEmpty()) from = item->childItems().first(); - else + else if (!isTabFence) from = item->parentItem(); } bool skip = false; QQuickItem * startItem = item; QQuickItem * firstFromItem = from; QQuickItem *current = item; + qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: startItem:" << startItem; + qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: firstFromItem:" << firstFromItem; do { + qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: current:" << current; + qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: from:" << from; skip = false; QQuickItem *last = current; @@ -2507,7 +2518,7 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo else lastChild = prevTabChildItem(current, -1); } - bool isTabFence = current->d_func()->isTabFence; + isTabFence = current->d_func()->isTabFence; if (isTabFence && !hasChildren) return current; @@ -2562,9 +2573,14 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo return startItem; } } - if (!firstFromItem) { //start from root - startItem = current; - firstFromItem = from; + if (!firstFromItem) { + if (startItem->d_func()->isTabFence) { + if (current == startItem) + firstFromItem = from; + } else { //start from root + startItem = current; + firstFromItem = from; + } } } while (skip || !current->activeFocusOnTab() || !current->isEnabled() || !current->isVisible() || !(all || QQuickItemPrivate::canAcceptTabFocus(current))); @@ -5940,6 +5956,8 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt } break; case QQuickItem::ItemAntialiasingHasChanged: + // fall through + case QQuickItem::ItemDevicePixelRatioHasChanged: q->itemChange(change, data); break; } diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index d92910ce9c..bda6dd4da5 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -166,7 +166,8 @@ public: ItemOpacityHasChanged, // value.realValue ItemActiveFocusHasChanged, // value.boolValue ItemRotationHasChanged, // value.realValue - ItemAntialiasingHasChanged // value.boolValue + ItemAntialiasingHasChanged, // value.boolValue + ItemDevicePixelRatioHasChanged // value.realValue }; union ItemChangeData { diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 3aec464958..aa8f04e55d 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -1455,7 +1455,8 @@ void QQuickText::itemChange(ItemChange change, const ItemChangeData &value) { Q_D(QQuickText); Q_UNUSED(value); - if (change == ItemAntialiasingHasChanged) { + switch (change) { + case ItemAntialiasingHasChanged: if (!antialiasing()) d->font.setStyleStrategy(QFont::NoAntialias); else @@ -1463,6 +1464,22 @@ void QQuickText::itemChange(ItemChange change, const ItemChangeData &value) d->implicitWidthValid = false; d->implicitHeightValid = false; d->updateLayout(); + break; + + case ItemDevicePixelRatioHasChanged: + if (d->renderType == NativeRendering) { + // Native rendering optimizes for a given pixel grid, so its results must not be scaled. + // Text layout code respects the current device pixel ratio automatically, we only need + // to rerun layout after the ratio changed. + // Changes of implicit size should be minimal; they are hard to avoid. + d->implicitWidthValid = false; + d->implicitHeightValid = false; + d->updateLayout(); + } + break; + + default: + break; } QQuickItem::itemChange(change, value); } diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index b93aa06336..24bac168ea 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -285,10 +285,43 @@ void QQuickWindow::update() QQuickRenderControlPrivate::get(d->renderControl)->update(); } +static void updatePixelRatioHelper(QQuickItem *item, float pixelRatio) +{ + if (item->flags() & QQuickItem::ItemHasContents) { + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + itemPrivate->itemChange(QQuickItem::ItemDevicePixelRatioHasChanged, pixelRatio); + } + + QList <QQuickItem *> items = item->childItems(); + for (int i = 0; i < items.size(); ++i) + updatePixelRatioHelper(items.at(i), pixelRatio); +} + +void QQuickWindow::physicalDpiChanged() +{ + Q_D(QQuickWindow); + const qreal newPixelRatio = screen()->devicePixelRatio(); + if (qFuzzyCompare(newPixelRatio, d->devicePixelRatio)) + return; + d->devicePixelRatio = newPixelRatio; + if (d->contentItem) + updatePixelRatioHelper(d->contentItem, newPixelRatio); +} + void QQuickWindow::handleScreenChanged(QScreen *screen) { Q_D(QQuickWindow); - Q_UNUSED(screen) + if (screen) { + physicalDpiChanged(); + // When physical DPI changes on the same screen, either the resolution or the device pixel + // ratio changed. We must check what it is. Device pixel ratio does not have its own + // ...Changed() signal. + d->physicalDpiChangedConnection = connect(screen, SIGNAL(physicalDotsPerInchChanged(qreal)), + this, SLOT(physicalDpiChanged())); + } else { + disconnect(d->physicalDpiChangedConnection); + } + d->forcePolish(); } @@ -407,6 +440,7 @@ QQuickWindowPrivate::QQuickWindowPrivate() , touchMouseId(-1) , touchMousePressTimestamp(0) , dirtyItemList(0) + , devicePixelRatio(0) , context(0) , renderer(0) , windowManager(0) @@ -459,6 +493,9 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control) Q_ASSERT(windowManager || renderControl); + if (QScreen *screen = q->screen()) + devicePixelRatio = screen->devicePixelRatio(); + QSGContext *sg; if (renderControl) { QQuickRenderControlPrivate *renderControlPriv = QQuickRenderControlPrivate::get(renderControl); diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index 9f8ad095cd..d4ffb100de 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -196,6 +196,7 @@ protected: private Q_SLOTS: void maybeUpdate(); void cleanupSceneGraph(); + void physicalDpiChanged(); void handleScreenChanged(QScreen *screen); void setTransientParent_helper(QQuickWindow *window); void runJobsAfterSwap(); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 623707140e..787958ef86 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -205,6 +205,9 @@ public: QVector<QQuickItem *> itemsToPolish; + qreal devicePixelRatio; + QMetaObject::Connection physicalDpiChangedConnection; + void updateDirtyNodes(); void cleanupNodes(); void cleanupNodesOnShutdown(); diff --git a/src/quick/quick.pro b/src/quick/quick.pro index 4ff2d76a09..c8aa47d939 100644 --- a/src/quick/quick.pro +++ b/src/quick/quick.pro @@ -29,7 +29,7 @@ load(qt_module) include(util/util.pri) include(scenegraph/scenegraph.pri) include(items/items.pri) -include(designer/designer.pri) +!wince:include(designer/designer.pri) contains(QT_CONFIG, accessibility) { include(accessible/accessible.pri) } diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 39bc8b2e5f..35824c6d00 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -190,6 +190,8 @@ private slots: void argumentEvaluationOrder(); + void v4FunctionWithoutQML(); + signals: void testSignal(); }; @@ -3799,6 +3801,30 @@ void tst_QJSEngine::argumentEvaluationOrder() } +class TestObject : public QObject +{ + Q_OBJECT +public: + TestObject() : called(false) {} + + bool called; + + Q_INVOKABLE void callMe(QQmlV4Function *) { + called = true; + } +}; + +void tst_QJSEngine::v4FunctionWithoutQML() +{ + TestObject obj; + QJSEngine engine; + QJSValue wrapper = engine.newQObject(&obj); + QQmlEngine::setObjectOwnership(&obj, QQmlEngine::CppOwnership); + QVERIFY(!obj.called); + wrapper.property("callMe").call(); + QVERIFY(obj.called); +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" diff --git a/tests/auto/quick/qquickitem2/data/qtbug_50516_2_1.qml b/tests/auto/quick/qquickitem2/data/qtbug_50516_2_1.qml new file mode 100644 index 0000000000..d8b7833467 --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/qtbug_50516_2_1.qml @@ -0,0 +1,13 @@ +import QtQuick 2.1 +import Test 1.0 + +TabFence2 { + objectName: "root" + focus: true + width: 800 + height: 600 + Item { + objectName: "item" + focus: true + } +} diff --git a/tests/auto/quick/qquickitem2/data/qtbug_50516_2_2.qml b/tests/auto/quick/qquickitem2/data/qtbug_50516_2_2.qml new file mode 100644 index 0000000000..445dc6d2a1 --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/qtbug_50516_2_2.qml @@ -0,0 +1,12 @@ +import QtQuick 2.1 +import Test 1.0 + +TabFence2 { + objectName: "root" + focus: true + width: 800 + height: 600 + Item { + objectName: "item" + } +} diff --git a/tests/auto/quick/qquickitem2/data/qtbug_50516_2_3.qml b/tests/auto/quick/qquickitem2/data/qtbug_50516_2_3.qml new file mode 100644 index 0000000000..806d48ebeb --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/qtbug_50516_2_3.qml @@ -0,0 +1,16 @@ +import QtQuick 2.1 +import Test 1.0 + +TabFence2 { + objectName: "root" + focus: true + width: 800 + height: 600 + Item { + objectName: "item2" + focus: true + } + Item { + objectName: "item2" + } +} diff --git a/tests/auto/quick/qquickitem2/data/qtbug_50516_2_4.qml b/tests/auto/quick/qquickitem2/data/qtbug_50516_2_4.qml new file mode 100644 index 0000000000..6fcf513b51 --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/qtbug_50516_2_4.qml @@ -0,0 +1,15 @@ +import QtQuick 2.1 +import Test 1.0 + +TabFence2 { + objectName: "root" + focus: true + width: 800 + height: 600 + Item { + objectName: "item2" + } + Item { + objectName: "item2" + } +} diff --git a/tests/auto/quick/qquickitem2/data/qtbug_50516_2_5.qml b/tests/auto/quick/qquickitem2/data/qtbug_50516_2_5.qml new file mode 100644 index 0000000000..4f7b68a8de --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/qtbug_50516_2_5.qml @@ -0,0 +1,16 @@ +import QtQuick 2.1 +import Test 1.0 + +TabFence2 { + objectName: "root" + focus: true + width: 800 + height: 600 + TextInput { + objectName: "item1" + activeFocusOnTab: true + } + Item { + objectName: "item2" + } +} diff --git a/tests/auto/quick/qquickitem2/data/qtbug_50516_2_6.qml b/tests/auto/quick/qquickitem2/data/qtbug_50516_2_6.qml new file mode 100644 index 0000000000..223476327a --- /dev/null +++ b/tests/auto/quick/qquickitem2/data/qtbug_50516_2_6.qml @@ -0,0 +1,17 @@ +import QtQuick 2.1 +import Test 1.0 + +TabFence2 { + objectName: "root" + focus: true + width: 800 + height: 600 + TextInput { + objectName: "item1" + activeFocusOnTab: true + } + TextInput { + objectName: "item2" + activeFocusOnTab: true + } +} diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp index 8a75cba84a..58dca5c1a3 100644 --- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp +++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp @@ -75,6 +75,8 @@ private slots: void tabFence(); void qtbug_50516(); + void qtbug_50516_2_data(); + void qtbug_50516_2(); void keys(); void standardKeys_data(); @@ -309,6 +311,22 @@ public: QML_DECLARE_TYPE(TabFenceItem); +class TabFenceItem2 : public QQuickItem +{ + Q_OBJECT + +public: + TabFenceItem2(QQuickItem *parent = Q_NULLPTR) + : QQuickItem(parent) + { + QQuickItemPrivate *d = QQuickItemPrivate::get(this); + d->isTabFence = true; + setFlag(ItemIsFocusScope); + } +}; + +QML_DECLARE_TYPE(TabFenceItem2); + tst_QQuickItem::tst_QQuickItem() { } @@ -319,6 +337,7 @@ void tst_QQuickItem::initTestCase() qmlRegisterType<KeyTestItem>("Test",1,0,"KeyTestItem"); qmlRegisterType<HollowTestItem>("Test", 1, 0, "HollowTestItem"); qmlRegisterType<TabFenceItem>("Test", 1, 0, "TabFence"); + qmlRegisterType<TabFenceItem2>("Test", 1, 0, "TabFence2"); } void tst_QQuickItem::cleanup() @@ -1216,6 +1235,51 @@ void tst_QQuickItem::qtbug_50516() delete window; } +void tst_QQuickItem::qtbug_50516_2_data() +{ + QTest::addColumn<QString>("filename"); + QTest::addColumn<QString>("item1"); + QTest::addColumn<QString>("item2"); + + QTest::newRow("FocusScope TabFence with one Item(focused)") + << QStringLiteral("qtbug_50516_2_1.qml") << QStringLiteral("root") << QStringLiteral("root"); + QTest::newRow("FocusScope TabFence with one Item(unfocused)") + << QStringLiteral("qtbug_50516_2_2.qml") << QStringLiteral("root") << QStringLiteral("root"); + QTest::newRow("FocusScope TabFence with two Items(focused)") + << QStringLiteral("qtbug_50516_2_3.qml") << QStringLiteral("root") << QStringLiteral("root"); + QTest::newRow("FocusScope TabFence with two Items(unfocused)") + << QStringLiteral("qtbug_50516_2_4.qml") << QStringLiteral("root") << QStringLiteral("root"); + QTest::newRow("FocusScope TabFence with one Item and one TextInput(unfocused)") + << QStringLiteral("qtbug_50516_2_5.qml") << QStringLiteral("item1") << QStringLiteral("item1"); + QTest::newRow("FocusScope TabFence with two TextInputs(unfocused)") + << QStringLiteral("qtbug_50516_2_6.qml") << QStringLiteral("item1") << QStringLiteral("item2"); +} + +void tst_QQuickItem::qtbug_50516_2() +{ + QFETCH(QString, filename); + QFETCH(QString, item1); + QFETCH(QString, item2); + + QQuickView *window = new QQuickView(0); + window->setBaseSize(QSize(800,600)); + + window->setSource(testFileUrl(filename)); + window->show(); + window->requestActivate(); + QVERIFY(QTest::qWaitForWindowActive(window)); + QVERIFY(QGuiApplication::focusWindow() == window); + QVERIFY(window->rootObject()->hasActiveFocus()); + + QQuickItem *contentItem = window->rootObject(); + QQuickItem *next = contentItem->nextItemInFocusChain(true); + QCOMPARE(next->objectName(), item1); + next = contentItem->nextItemInFocusChain(false); + QCOMPARE(next->objectName(), item2); + + delete window; +} + void tst_QQuickItem::keys() { QQuickView *window = new QQuickView(0); |