aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-01-25 01:00:10 +0100
committerQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-01-25 01:00:11 +0100
commit9893e71cea5de10193376c1733db627ef0783614 (patch)
tree391fabceb9d4ff6ba5f3ff2c2ec42acb613eb4ef
parent87e7203532d69e0aaa0898a972d1d90fa589d519 (diff)
parente1b4b267aa8c4d9c53e5af4def54f5e9e14e0103 (diff)
Merge remote-tracking branch 'origin/5.15' into dev
-rw-r--r--examples/quick/shadereffects/content/shaders/+qsb/blur.fragbin2247 -> 1811 bytes
-rw-r--r--examples/quick/shadereffects/content/shaders/+qsb/colorize.fragbin2106 -> 1701 bytes
-rw-r--r--examples/quick/shadereffects/content/shaders/+qsb/genie.vertbin2629 -> 2201 bytes
-rw-r--r--examples/quick/shadereffects/content/shaders/+qsb/outline.fragbin2538 -> 2117 bytes
-rw-r--r--examples/quick/shadereffects/content/shaders/+qsb/shadow.fragbin2151 -> 1745 bytes
-rw-r--r--examples/quick/shadereffects/content/shaders/+qsb/wobble.fragbin2049 -> 1625 bytes
-rw-r--r--examples/quick/shapes/content/item18.qml71
-rw-r--r--examples/quick/shapes/content/shapegallery.qml4
-rw-r--r--examples/quick/shapes/shapes.pro3
-rw-r--r--examples/quick/shapes/shapes.qrc1
-rw-r--r--src/imports/imports.pro5
-rw-r--r--src/imports/labsmodels/qqmldelegatecomponent.cpp12
-rw-r--r--src/imports/layouts/qquicklayout_p.h2
-rw-r--r--src/particles/shaders_ng/imageparticle_colored.frag.qsbbin1572 -> 1506 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_colored.vert.qsbbin3329 -> 3293 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_deformed.frag.qsbbin1601 -> 1516 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_deformed.vert.qsbbin4712 -> 4641 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_simple.frag.qsbbin1581 -> 1512 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_simple.vert.qsbbin3261 -> 3160 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_sprite.frag.qsbbin1918 -> 1846 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_sprite.vert.qsbbin5367 -> 5330 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_tabled.frag.qsbbin1777 -> 1709 bytes
-rw-r--r--src/particles/shaders_ng/imageparticle_tabled.vert.qsbbin4929 -> 4987 bytes
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp2
-rw-r--r--src/qml/common/qv4compileddata_p.h51
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp57
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h18
-rw-r--r--src/qml/debugger/qqmldebug.cpp10
-rw-r--r--src/qml/inlinecomponentutils_p.h161
-rw-r--r--src/qml/jsapi/qjsengine.cpp38
-rw-r--r--src/qml/jsapi/qjsengine.h7
-rw-r--r--src/qml/jsapi/qjsengine_p.h1
-rw-r--r--src/qml/jsruntime/qv4engine.cpp3
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp111
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit_p.h37
-rw-r--r--src/qml/parser/qqmljs.g64
-rw-r--r--src/qml/parser/qqmljsast.cpp9
-rw-r--r--src/qml/parser/qqmljsast_p.h23
-rw-r--r--src/qml/parser/qqmljsastfwd_p.h1
-rw-r--r--src/qml/parser/qqmljsastvisitor_p.h2
-rw-r--r--src/qml/parser/qqmljskeywords_p.h19
-rw-r--r--src/qml/qml.pro1
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp37
-rw-r--r--src/qml/qml/qqmlapplicationengine.h1
-rw-r--r--src/qml/qml/qqmlapplicationengine_p.h4
-rw-r--r--src/qml/qml/qqmlengine.cpp45
-rw-r--r--src/qml/qml/qqmlengine_p.h1
-rw-r--r--src/qml/qml/qqmlimport.cpp173
-rw-r--r--src/qml/qml/qqmlimport_p.h4
-rw-r--r--src/qml/qml/qqmlirloader.cpp7
-rw-r--r--src/qml/qml/qqmlmetatype.cpp4
-rw-r--r--src/qml/qml/qqmlmetatype_p.h21
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp59
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h3
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp32
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h110
-rw-r--r--src/qml/qml/qqmlpropertydata_p.h191
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp3
-rw-r--r--src/qml/qml/qqmltype.cpp113
-rw-r--r--src/qml/qml/qqmltype_p.h16
-rw-r--r--src/qml/qml/qqmltype_p_p.h19
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp10
-rw-r--r--src/qml/qml/qqmltypecompiler_p.h11
-rw-r--r--src/qml/qml/qqmltypedata.cpp201
-rw-r--r--src/qml/qml/qqmltypedata_p.h14
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp43
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h2
-rw-r--r--src/qmltest/quicktestresult.cpp14
-rw-r--r--src/qmlworkerscript/qquickworkerscript.cpp2
-rw-r--r--src/quick/configure.json2
-rw-r--r--src/quick/items/qquickborderimage.cpp92
-rw-r--r--src/quick/items/qquickimagebase.cpp138
-rw-r--r--src/quick/items/qquickimagebase_p.h11
-rw-r--r--src/quick/items/qquickitem.cpp252
-rw-r--r--src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsbbin1537 -> 1469 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsbbin1399 -> 1344 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsbbin1405 -> 1351 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsbbin909 -> 845 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag.qsbbin1820 -> 1783 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsbbin1851 -> 1802 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag.qsbbin1814 -> 1780 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag.qsbbin1905 -> 1867 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsbbin1951 -> 1930 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag.qsbbin1914 -> 1858 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldtext.frag.qsbbin1538 -> 1488 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldtext.vert.qsbbin1709 -> 1692 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag.qsbbin1542 -> 1479 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/flatcolor.frag.qsbbin917 -> 864 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/flatcolor.vert.qsbbin1334 -> 1284 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag.qsbbin2898 -> 2848 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.vert.qsbbin3288 -> 3282 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag.qsbbin2909 -> 2863 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag.qsbbin2015 -> 1971 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.vert.qsbbin2675 -> 2614 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag.qsbbin2024 -> 1979 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/opaquetexture.frag.qsbbin967 -> 927 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/opaquetexture.vert.qsbbin1500 -> 1469 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsbbin2162 -> 2107 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsbbin2599 -> 2623 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsbbin1436 -> 1402 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/shadereffect.frag.qsbbin1307 -> 1247 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/shadereffect.vert.qsbbin1561 -> 1501 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/smoothcolor.frag.qsbbin700 -> 672 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/smoothcolor.vert.qsbbin3390 -> 3320 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/smoothtexture.frag.qsbbin1073 -> 1038 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/smoothtexture.vert.qsbbin3957 -> 3954 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/sprite.frag.qsbbin1571 -> 1498 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/sprite.vert.qsbbin2127 -> 2087 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/stencilclip.frag.qsbbin737 -> 715 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/stencilclip.vert.qsbbin1279 -> 1230 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext.frag.qsbbin1805 -> 1740 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext.vert.qsbbin2209 -> 2175 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsbbin1212 -> 1158 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/textmask.frag.qsbbin1533 -> 1469 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/textmask.vert.qsbbin1961 -> 1933 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/texture.frag.qsbbin1302 -> 1242 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/texture.vert.qsbbin1561 -> 1516 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/vertexcolor.frag.qsbbin700 -> 672 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/vertexcolor.vert.qsbbin1542 -> 1507 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/visualization.frag.qsbbin1569 -> 1504 bytes
-rw-r--r--src/quick/scenegraph/shaders_ng/visualization.vert.qsbbin1762 -> 1704 bytes
-rw-r--r--src/quick/util/qquickimageprovider.cpp8
-rw-r--r--src/quick/util/qquickpath.cpp223
-rw-r--r--src/quick/util/qquickpath_p.h102
-rw-r--r--src/quick/util/qquickpath_p_p.h1
-rw-r--r--src/quickshapes/qquickshapegenericrenderer_p.h1
-rw-r--r--src/quickshapes/shaders_ng/conicalgradient.frag.qsbbin1889 -> 1843 bytes
-rw-r--r--src/quickshapes/shaders_ng/conicalgradient.vert.qsbbin1684 -> 1662 bytes
-rw-r--r--src/quickshapes/shaders_ng/lineargradient.frag.qsbbin1423 -> 1363 bytes
-rw-r--r--src/quickshapes/shaders_ng/lineargradient.vert.qsbbin1895 -> 1869 bytes
-rw-r--r--src/quickshapes/shaders_ng/radialgradient.frag.qsbbin2579 -> 2539 bytes
-rw-r--r--src/quickshapes/shaders_ng/radialgradient.vert.qsbbin1774 -> 1779 bytes
-rw-r--r--tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp3
-rw-r--r--tests/auto/qml/ecmascripttests/BLACKLIST4
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp29
-rw-r--r--tests/auto/qml/qqmlapplicationengine/data/i18n/qml_de_CH.qmbin0 -> 101 bytes
-rw-r--r--tests/auto/qml/qqmlapplicationengine/data/i18n/qml_de_CH.ts11
-rw-r--r--tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp23
-rw-r--r--tests/auto/qml/qqmlengine/data/uiLanguage.qml9
-rw-r--r--tests/auto/qml/qqmlengine/tst_qqmlengine.cpp33
-rw-r--r--tests/auto/qml/qqmllanguage/data/InlineComponentBase.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/InlineComponentChild.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/InlineComponentProvider.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/InlineComponentProvider2.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/InlineComponentProvider3.qml11
-rw-r--r--tests/auto/qml/qqmllanguage/data/InlineComponentProviderChild.qml1
-rw-r--r--tests/auto/qml/qqmllanguage/data/InlineComponentReexporter.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/icCycleViaProperty.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/icSimpleCycle.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/inlineComponentOrder.qml20
-rw-r--r--tests/auto/qml/qqmllanguage/data/inlineComponentUser1.qml13
-rw-r--r--tests/auto/qml/qqmllanguage/data/inlineComponentUser2.qml10
-rw-r--r--tests/auto/qml/qqmllanguage/data/inlineComponentUser3.qml16
-rw-r--r--tests/auto/qml/qqmllanguage/data/inlineComponentUser4.qml12
-rw-r--r--tests/auto/qml/qqmllanguage/data/inlineComponentUser5.qml11
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidRoot.4.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/invalidTypeName.4.errors.txt2
-rw-r--r--tests/auto/qml/qqmllanguage/data/nestedIC.qml7
-rw-r--r--tests/auto/qml/qqmllanguage/data/nonExistingICUser1.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/nonExistingICUser2.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/nonExistingICUser3.qml3
-rw-r--r--tests/auto/qml/qqmllanguage/data/nonExistingICUser4.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/data/nonExistingICUser5.qml5
-rw-r--r--tests/auto/qml/qqmllanguage/data/singleton/SingletonTypeWithIC.qml16
-rw-r--r--tests/auto/qml/qqmllanguage/data/singleton/qmldir1
-rw-r--r--tests/auto/qml/qqmllanguage/data/singletonICTest.qml6
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp136
-rw-r--r--tests/auto/qml/qqmllistmodel/qqmllistmodel.pro2
-rw-r--r--tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp2
-rw-r--r--tests/auto/qmltest/animatedimage/BLACKLIST2
-rw-r--r--tests/auto/qmltest/listview/data/MultiDelegate3.qml97
-rw-r--r--tests/auto/qmltest/listview/tst_listview.qml17
-rw-r--r--tests/auto/qmltest/textedit/BLACKLIST4
-rw-r--r--tests/auto/quick/qquickcanvasitem/BLACKLIST14
-rw-r--r--tests/auto/quick/qquickitem2/data/mapCoordinates.qml20
-rw-r--r--tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml10
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp24
-rw-r--r--tests/auto/quick/qquicklistview/BLACKLIST4
-rw-r--r--tests/auto/quick/qquicktext/BLACKLIST2
-rwxr-xr-xtests/manual/nodetypes_ng/compile.bat (renamed from tests/manual/nodetypes_ng/buildshaders.bat)0
-rw-r--r--tests/manual/nodetypes_ng/shadow_pass1.frag.qsbbin1876 -> 1822 bytes
-rw-r--r--tests/manual/nodetypes_ng/shadow_pass2.frag.qsbbin1790 -> 1745 bytes
-rw-r--r--tests/manual/nodetypes_ng/wobble.frag.qsbbin1673 -> 1627 bytes
-rw-r--r--tests/manual/nodetypes_ng/wobble.vert.qsbbin1678 -> 1641 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/basic.fragbin838 -> 813 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/cmyk.fragbin1959 -> 1923 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/culling.fragbin1263 -> 1238 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/edge.fragbin1890 -> 1831 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient.fragbin1099 -> 1061 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient2.fragbin1089 -> 1064 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient3.fragbin1089 -> 1059 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient4.fragbin1092 -> 1057 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient5.fragbin1089 -> 1050 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/shadow.fragbin2092 -> 2041 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/stencil.fragbin1141 -> 1122 bytes
-rw-r--r--tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/wave.vertbin1867 -> 1799 bytes
-rw-r--r--tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in10
198 files changed, 2799 insertions, 552 deletions
diff --git a/examples/quick/shadereffects/content/shaders/+qsb/blur.frag b/examples/quick/shadereffects/content/shaders/+qsb/blur.frag
index 1c79359297..d29b2d4365 100644
--- a/examples/quick/shadereffects/content/shaders/+qsb/blur.frag
+++ b/examples/quick/shadereffects/content/shaders/+qsb/blur.frag
Binary files differ
diff --git a/examples/quick/shadereffects/content/shaders/+qsb/colorize.frag b/examples/quick/shadereffects/content/shaders/+qsb/colorize.frag
index 45c5301f31..58bb5aaa8e 100644
--- a/examples/quick/shadereffects/content/shaders/+qsb/colorize.frag
+++ b/examples/quick/shadereffects/content/shaders/+qsb/colorize.frag
Binary files differ
diff --git a/examples/quick/shadereffects/content/shaders/+qsb/genie.vert b/examples/quick/shadereffects/content/shaders/+qsb/genie.vert
index dd94129cf7..540cb6a85b 100644
--- a/examples/quick/shadereffects/content/shaders/+qsb/genie.vert
+++ b/examples/quick/shadereffects/content/shaders/+qsb/genie.vert
Binary files differ
diff --git a/examples/quick/shadereffects/content/shaders/+qsb/outline.frag b/examples/quick/shadereffects/content/shaders/+qsb/outline.frag
index 470e2bd6e6..633fe0f926 100644
--- a/examples/quick/shadereffects/content/shaders/+qsb/outline.frag
+++ b/examples/quick/shadereffects/content/shaders/+qsb/outline.frag
Binary files differ
diff --git a/examples/quick/shadereffects/content/shaders/+qsb/shadow.frag b/examples/quick/shadereffects/content/shaders/+qsb/shadow.frag
index 128af21daa..8059fab6ac 100644
--- a/examples/quick/shadereffects/content/shaders/+qsb/shadow.frag
+++ b/examples/quick/shadereffects/content/shaders/+qsb/shadow.frag
Binary files differ
diff --git a/examples/quick/shadereffects/content/shaders/+qsb/wobble.frag b/examples/quick/shadereffects/content/shaders/+qsb/wobble.frag
index 9b27ae87cb..85fb453659 100644
--- a/examples/quick/shadereffects/content/shaders/+qsb/wobble.frag
+++ b/examples/quick/shadereffects/content/shaders/+qsb/wobble.frag
Binary files differ
diff --git a/examples/quick/shapes/content/item18.qml b/examples/quick/shapes/content/item18.qml
new file mode 100644
index 0000000000..3774d19bc5
--- /dev/null
+++ b/examples/quick/shapes/content/item18.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, 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 The Qt Company Ltd 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$
+**
+****************************************************************************/
+
+import QtQuick 2.15
+import QtQuick.Shapes 1.0
+
+Rectangle {
+ color: "lightGray"
+
+ Shape {
+ anchors.centerIn: parent
+ width: 200
+ height: 100
+
+ ShapePath {
+ id: capTest
+ strokeColor: "black"
+ strokeWidth: 1
+ fillColor: "black"
+
+ PathText { x: 0; y: 100; font.family: "Arial"; font.pixelSize: 150; text: "Qt!" }
+ }
+ }
+}
diff --git a/examples/quick/shapes/content/shapegallery.qml b/examples/quick/shapes/content/shapegallery.qml
index 86445e25c2..e5a7c51483 100644
--- a/examples/quick/shapes/content/shapegallery.qml
+++ b/examples/quick/shapes/content/shapegallery.qml
@@ -130,6 +130,10 @@ Rectangle {
name: "Tiger"
shapeUrl: "item17.qml"
}
+ ListElement {
+ name: "Text"
+ shapeUrl: "item18.qml"
+ }
}
property int gridSpacing: 10
diff --git a/examples/quick/shapes/shapes.pro b/examples/quick/shapes/shapes.pro
index ff6fa422fb..f99d941804 100644
--- a/examples/quick/shapes/shapes.pro
+++ b/examples/quick/shapes/shapes.pro
@@ -24,7 +24,8 @@ OTHER_FILES += content/main.qml \
content/item13.qml \
content/item14.qml \
content/item15.qml \
- content/item17.qml
+ content/item17.qml \
+ content/item18.qml
target.path = $$[QT_INSTALL_EXAMPLES]/quick/shapes
INSTALLS += target
diff --git a/examples/quick/shapes/shapes.qrc b/examples/quick/shapes/shapes.qrc
index e03c0e8a0a..6de463dd33 100644
--- a/examples/quick/shapes/shapes.qrc
+++ b/examples/quick/shapes/shapes.qrc
@@ -28,5 +28,6 @@
<file alias="item14.qml">content/item14.qml</file>
<file alias="item15.qml">content/item15.qml</file>
<file alias="item17.qml">content/item17.qml</file>
+ <file alias="item18.qml">content/item18.qml</file>
</qresource>
</RCC>
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index 9973883024..e0f66838ec 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -20,8 +20,9 @@ qtHaveModule(quick) {
labsanimation \
layouts \
qtquick2 \
- window \
- wavefrontmesh
+ window
+
+ qtConfig(quick-shadereffect): SUBDIRS += wavefrontmesh
qtHaveModule(testlib): SUBDIRS += testlib
qtConfig(systemsemaphore): SUBDIRS += sharedimage
diff --git a/src/imports/labsmodels/qqmldelegatecomponent.cpp b/src/imports/labsmodels/qqmldelegatecomponent.cpp
index 4698287fe3..aaf3fea5da 100644
--- a/src/imports/labsmodels/qqmldelegatecomponent.cpp
+++ b/src/imports/labsmodels/qqmldelegatecomponent.cpp
@@ -218,7 +218,7 @@ bool QQmlDelegateChoice::match(int row, int column, const QVariant &value) const
/*!
\qmlproperty string QtQml.Models::DelegateChooser::role
- This property holds the role used to determine the delegate for a given model item.
+ This property holds the role or the property name used to determine the delegate for a given model item.
\sa DelegateChoice
*/
@@ -289,9 +289,15 @@ QQmlComponent *QQmlDelegateChooser::delegate(QQmlAdaptorModel *adaptorModel, int
v = value(adaptorModel, row, column, m_role);
if (!v.isValid()) { // check if the row only has modelData, for example if the row is a QVariantMap
v = value(adaptorModel, row, column, QStringLiteral("modelData"));
- if (v.isValid())
- v = v.toMap().value(m_role);
+
+ if (v.isValid()) {
+ if (v.canConvert(QMetaType::QVariantMap))
+ v = v.toMap().value(m_role);
+ else if (v.canConvert(QMetaType::QObjectStar))
+ v = v.value<QObject*>()->property(m_role.toUtf8());
+ }
}
+
// loop through choices, finding first one that fits
for (int i = 0; i < m_choices.count(); ++i) {
const QQmlDelegateChoice *choice = m_choices.at(i);
diff --git a/src/imports/layouts/qquicklayout_p.h b/src/imports/layouts/qquicklayout_p.h
index c022a2fd47..cb46c41e6c 100644
--- a/src/imports/layouts/qquicklayout_p.h
+++ b/src/imports/layouts/qquicklayout_p.h
@@ -135,7 +135,7 @@ class QQuickLayoutPrivate : public QQuickItemPrivate
{
Q_DECLARE_PUBLIC(QQuickLayout)
public:
- QQuickLayoutPrivate() : m_isReady(false), m_disableRearrange(true) {}
+ QQuickLayoutPrivate() : m_isReady(false), m_disableRearrange(true), m_hasItemChangeListeners(false) {}
protected:
unsigned m_isReady : 1;
diff --git a/src/particles/shaders_ng/imageparticle_colored.frag.qsb b/src/particles/shaders_ng/imageparticle_colored.frag.qsb
index aa6ae5c6bc..106109271e 100644
--- a/src/particles/shaders_ng/imageparticle_colored.frag.qsb
+++ b/src/particles/shaders_ng/imageparticle_colored.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_colored.vert.qsb b/src/particles/shaders_ng/imageparticle_colored.vert.qsb
index a07c8d0e79..e29c1029c1 100644
--- a/src/particles/shaders_ng/imageparticle_colored.vert.qsb
+++ b/src/particles/shaders_ng/imageparticle_colored.vert.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_deformed.frag.qsb b/src/particles/shaders_ng/imageparticle_deformed.frag.qsb
index 1f4a08fe48..d2f74b40df 100644
--- a/src/particles/shaders_ng/imageparticle_deformed.frag.qsb
+++ b/src/particles/shaders_ng/imageparticle_deformed.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_deformed.vert.qsb b/src/particles/shaders_ng/imageparticle_deformed.vert.qsb
index 6a2048c5bf..c2e5bab0cb 100644
--- a/src/particles/shaders_ng/imageparticle_deformed.vert.qsb
+++ b/src/particles/shaders_ng/imageparticle_deformed.vert.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_simple.frag.qsb b/src/particles/shaders_ng/imageparticle_simple.frag.qsb
index f580048e71..8031dc8765 100644
--- a/src/particles/shaders_ng/imageparticle_simple.frag.qsb
+++ b/src/particles/shaders_ng/imageparticle_simple.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_simple.vert.qsb b/src/particles/shaders_ng/imageparticle_simple.vert.qsb
index 6735e1ae38..03f71415f5 100644
--- a/src/particles/shaders_ng/imageparticle_simple.vert.qsb
+++ b/src/particles/shaders_ng/imageparticle_simple.vert.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_sprite.frag.qsb b/src/particles/shaders_ng/imageparticle_sprite.frag.qsb
index 01806a3c54..847de59aa6 100644
--- a/src/particles/shaders_ng/imageparticle_sprite.frag.qsb
+++ b/src/particles/shaders_ng/imageparticle_sprite.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_sprite.vert.qsb b/src/particles/shaders_ng/imageparticle_sprite.vert.qsb
index 6d8c1852f5..e310af8fc8 100644
--- a/src/particles/shaders_ng/imageparticle_sprite.vert.qsb
+++ b/src/particles/shaders_ng/imageparticle_sprite.vert.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_tabled.frag.qsb b/src/particles/shaders_ng/imageparticle_tabled.frag.qsb
index 630fb064ac..6fe2d5a3f2 100644
--- a/src/particles/shaders_ng/imageparticle_tabled.frag.qsb
+++ b/src/particles/shaders_ng/imageparticle_tabled.frag.qsb
Binary files differ
diff --git a/src/particles/shaders_ng/imageparticle_tabled.vert.qsb b/src/particles/shaders_ng/imageparticle_tabled.vert.qsb
index af0f475bb8..740f6b6769 100644
--- a/src/particles/shaders_ng/imageparticle_tabled.vert.qsb
+++ b/src/particles/shaders_ng/imageparticle_tabled.vert.qsb
Binary files differ
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
index a688e98b3f..4702bc3c33 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
@@ -153,7 +153,7 @@ void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data,
if (locations.isEmpty())
locations = new_locations;
else
- locations.unite(new_locations);
+ locations.insert(new_locations);
service->dataReady(this);
}
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp
index 12c36f3dd6..fb2a28ea01 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp
@@ -168,7 +168,7 @@ void QV4ProfilerAdapter::receiveData(
if (m_functionLocations.isEmpty())
m_functionLocations = locations;
else
- m_functionLocations.unite(locations);
+ m_functionLocations.insert(locations);
if (m_functionCallData.isEmpty())
m_functionCallData = functionCallData;
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index 3e5e4ae11e..1480df2817 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -76,7 +76,7 @@ QT_BEGIN_NAMESPACE
// Also change the comment behind the number to describe the latest change. This has the added
// benefit that if another patch changes the version too, it will result in a merge conflict, and
// not get removed silently.
-#define QV4_DATA_STRUCTURE_VERSION 0x27 // resolved merge
+#define QV4_DATA_STRUCTURE_VERSION 0x28// support inline components
class QIODevice;
class QQmlTypeNameCache;
@@ -113,6 +113,7 @@ struct TableIterator
int index;
const ItemType *operator->() { return (container->*IndexedGetter)(index); }
+ ItemType operator*() {return *operator->();}
void operator++() { ++index; }
bool operator==(const TableIterator &rhs) const { return index == rhs.index; }
bool operator!=(const TableIterator &rhs) const { return index != rhs.index; }
@@ -573,6 +574,15 @@ struct Binding
static_assert(sizeof(Binding) == 24, "Binding structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+struct InlineComponent
+{
+ quint32_le objectIndex;
+ quint32_le nameIndex;
+ Location location;
+};
+
+static_assert(sizeof(InlineComponent) == 12, "InlineComponent structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+
struct EnumValue
{
quint32_le nameIndex;
@@ -697,7 +707,9 @@ struct Object
NoFlag = 0x0,
IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
HasDeferredBindings = 0x2, // any of the bindings are deferred
- HasCustomParserBindings = 0x4
+ HasCustomParserBindings = 0x4,
+ IsInlineComponentRoot = 0x8,
+ InPartOfInlineComponent = 0x10
};
// Depending on the use, this may be the type name to instantiate before instantiating this
@@ -727,12 +739,15 @@ struct Object
quint32_le offsetToNamedObjectsInComponent;
Location location;
Location locationOfIdProperty;
+ quint32_le offsetToInlineComponents;
+ quint16_le nInlineComponents;
// Function[]
// Property[]
// Signal[]
// Binding[]
+// InlineComponent[]
- static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent)
+ static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents)
{
return ( sizeof(Object)
+ nFunctions * sizeof(quint32)
@@ -742,6 +757,7 @@ struct Object
+ nSignals * sizeof(quint32)
+ nBindings * sizeof(Binding)
+ nNamedObjectsInComponent * sizeof(int)
+ + nInlineComponents * sizeof(InlineComponent)
+ 0x7
) & ~0x7;
}
@@ -780,11 +796,21 @@ struct Object
return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
}
+ const InlineComponent *inlineComponentAt(int idx) const
+ {
+ return inlineComponentTable() + idx;
+ }
+
const quint32_le *namedObjectsInComponentTable() const
{
return reinterpret_cast<const quint32_le*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
}
+ const InlineComponent *inlineComponentTable() const
+ {
+ return reinterpret_cast<const InlineComponent*>(reinterpret_cast<const char *>(this) + offsetToInlineComponents);
+ }
+
// --- QQmlPropertyCacheCreator interface
int propertyCount() const { return nProperties; }
int aliasCount() const { return nAliases; }
@@ -809,17 +835,22 @@ struct Object
SignalIterator signalsBegin() const { return SignalIterator(this, 0); }
SignalIterator signalsEnd() const { return SignalIterator(this, nSignals); }
+ typedef TableIterator<InlineComponent, Object, &Object::inlineComponentAt> InlineComponentIterator;
+ InlineComponentIterator inlineComponentsBegin() const {return InlineComponentIterator(this, 0);}
+ InlineComponentIterator inlineComponentsEnd() const {return InlineComponentIterator(this, nInlineComponents);}
+
int namedObjectsInComponentCount() const { return nNamedObjectsInComponent; }
// ---
};
-static_assert(sizeof(Object) == 68, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
+static_assert(sizeof(Object) == 76, "Object structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Import
{
enum ImportType : unsigned int {
ImportLibrary = 0x1,
ImportFile = 0x2,
- ImportScript = 0x3
+ ImportScript = 0x3,
+ ImportInlineComponent = 0x4
};
quint32_le type;
@@ -1047,7 +1078,7 @@ struct TypeReferenceMap : QHash<int, TypeReference>
}
auto prop = obj->propertiesBegin();
- auto propEnd = obj->propertiesEnd();
+ auto const propEnd = obj->propertiesEnd();
for ( ; prop != propEnd; ++prop) {
if (!prop->isBuiltinType) {
TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex, prop->location);
@@ -1056,11 +1087,17 @@ struct TypeReferenceMap : QHash<int, TypeReference>
}
auto binding = obj->bindingsBegin();
- auto bindingEnd = obj->bindingsEnd();
+ auto const bindingEnd = obj->bindingsEnd();
for ( ; binding != bindingEnd; ++binding) {
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
this->add(binding->propertyNameIndex, binding->location);
}
+
+ auto ic = obj->inlineComponentsBegin();
+ auto const icEnd = obj->inlineComponentsEnd();
+ for (; ic != icEnd; ++ic) {
+ this->add(ic->nameIndex, ic->location);
+ }
}
template <typename Iterator>
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 9623d2ed58..811f88cb73 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -161,6 +161,7 @@ void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, cons
bindings = pool->New<PoolList<Binding> >();
functions = pool->New<PoolList<Function> >();
functionsAndExpressions = pool->New<PoolList<CompiledFunctionOrExpression> >();
+ inlineComponents = pool->New<PoolList<InlineComponent>>();
declarationsOverride = nullptr;
}
@@ -281,6 +282,11 @@ void Object::appendFunction(QmlIR::Function *f)
target->functions->append(f);
}
+void Object::appendInlineComponent(InlineComponent *ic)
+{
+ inlineComponents->append(ic);
+}
+
QString Object::appendBinding(Binding *b, bool isListBinding)
{
const bool bindingToDefaultProperty = (b->propertyNameIndex == quint32(0));
@@ -503,6 +509,33 @@ bool IRBuilder::visit(QQmlJS::AST::UiObjectDefinition *node)
return false;
}
+bool IRBuilder::visit(QQmlJS::AST::UiInlineComponent *ast)
+{
+ int idx = -1;
+ if (insideInlineComponent) {
+ recordError(ast->firstSourceLocation(), QLatin1String("Nested inline components are not supported"));
+ return false;
+ }
+ {
+ QScopedValueRollback<bool> rollBack {insideInlineComponent, true};
+ if (!defineQMLObject(&idx, ast->component))
+ return false;
+ }
+ Q_ASSERT(idx > 0);
+ Object* definedObject = _objects.at(idx);
+ definedObject->flags |= QV4::CompiledData::Object::IsInlineComponentRoot;
+ definedObject->flags |= QV4::CompiledData::Object::InPartOfInlineComponent;
+ definedObject->isInlineComponent = true;
+ auto inlineComponent = New<InlineComponent>();
+ inlineComponent->nameIndex = registerString(ast->name.toString());
+ inlineComponent->objectIndex = idx;
+ auto location = ast->firstSourceLocation();
+ inlineComponent->location.line = location.startLine;
+ inlineComponent->location.column = location.startColumn;
+ _object->appendInlineComponent(inlineComponent);
+ return false;
+}
+
bool IRBuilder::visit(QQmlJS::AST::UiObjectBinding *node)
{
int idx = 0;
@@ -597,12 +630,16 @@ bool IRBuilder::defineQMLObject(int *objectIndex, QQmlJS::AST::UiQualifiedId *qu
}
Object *obj = New<Object>();
+
_objects.append(obj);
*objectIndex = _objects.size() - 1;
qSwap(_object, obj);
_object->init(pool, registerString(asString(qualifiedTypeNameId)), emptyStringIndex, location);
_object->declarationsOverride = declarationsOverride;
+ if (insideInlineComponent) {
+ _object->flags |= QV4::CompiledData::Object::InPartOfInlineComponent;
+ }
// A new object is also a boundary for property declarations.
Property *declaration = nullptr;
@@ -1553,7 +1590,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
uint nextOffset = objectOffset + objectOffsetTableSize;
for (Object *o : qAsConst(output.objects)) {
objectOffsets.insert(o, nextOffset);
- nextOffset += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.size());
+ nextOffset += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.size(), o->inlineComponentCount());
int signalTableSize = 0;
for (const Signal *s = o->firstSignal(); s; s = s->next)
@@ -1632,6 +1669,10 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
objectToWrite->offsetToNamedObjectsInComponent = nextOffset;
nextOffset += objectToWrite->nNamedObjectsInComponent * sizeof(quint32);
+ objectToWrite->nInlineComponents = o->inlineComponentCount();
+ objectToWrite->offsetToInlineComponents = nextOffset;
+ nextOffset += objectToWrite->nInlineComponents * sizeof (QV4::CompiledData::InlineComponent);
+
quint32_le *functionsTable = reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToFunctions);
for (const Function *f = o->firstFunction(); f; f = f->next)
*functionsTable++ = o->runtimeFunctionIndices.at(f->index);
@@ -1703,6 +1744,14 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
for (int i = 0; i < o->namedObjectsInComponent.size(); ++i) {
*namedObjectInComponentPtr++ = o->namedObjectsInComponent.at(i);
}
+
+ char *inlineComponentPtr = objectPtr + objectToWrite->offsetToInlineComponents;
+ for (auto it = o->inlineComponentsBegin(); it != o->inlineComponentsEnd(); ++it) {
+ const InlineComponent *ic = it.ptr;
+ QV4::CompiledData::InlineComponent *icToWrite = reinterpret_cast<QV4::CompiledData::InlineComponent*>(inlineComponentPtr);
+ *icToWrite = *ic;
+ inlineComponentPtr += sizeof(QV4::CompiledData::InlineComponent);
+ }
}
if (!output.javaScriptCompilationUnit.data) {
@@ -1850,12 +1899,14 @@ bool JSCodeGen::generateCodeForComponents(const QVector<quint32> &componentRoots
bool JSCodeGen::compileComponent(int contextObject)
{
const QmlIR::Object *obj = document->objects.at(contextObject);
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ if (obj->flags & QV4::CompiledData::Object::IsComponent && !obj->isInlineComponent) {
Q_ASSERT(obj->bindingCount() == 1);
const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
contextObject = componentBinding->value.objectIndex;
}
+ for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it)
+ compileComponent(it->objectIndex);
return compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject);
}
@@ -1863,7 +1914,7 @@ bool JSCodeGen::compileComponent(int contextObject)
bool JSCodeGen::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
{
QmlIR::Object *object = document->objects.at(objectIndex);
- if (object->flags & QV4::CompiledData::Object::IsComponent)
+ if (object->flags & QV4::CompiledData::Object::IsComponent && !object->isInlineComponent)
return true;
if (object->functionsAndExpressions->count > 0) {
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index ab0ddf6ef8..d4f2eb8dd4 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -275,6 +275,11 @@ struct Binding : public QV4::CompiledData::Binding
Binding *next;
};
+struct InlineComponent : public QV4::CompiledData::InlineComponent
+{
+ InlineComponent *next;
+};
+
struct Alias : public QV4::CompiledData::Alias
{
Alias *next;
@@ -316,6 +321,7 @@ public:
int id;
int indexOfDefaultPropertyOrAlias;
bool defaultPropertyIsAlias;
+ bool isInlineComponent = false;
quint32 flags;
QV4::CompiledData::Location location;
@@ -333,6 +339,8 @@ public:
int bindingCount() const { return bindings->count; }
const Function *firstFunction() const { return functions->first; }
int functionCount() const { return functions->count; }
+ const InlineComponent *inlineComponent() const { return inlineComponents->first; }
+ int inlineComponentCount() const { return inlineComponents->count; }
PoolList<Binding>::Iterator bindingsBegin() const { return bindings->begin(); }
PoolList<Binding>::Iterator bindingsEnd() const { return bindings->end(); }
@@ -346,6 +354,8 @@ public:
PoolList<Signal>::Iterator signalsEnd() const { return qmlSignals->end(); }
PoolList<Function>::Iterator functionsBegin() const { return functions->begin(); }
PoolList<Function>::Iterator functionsEnd() const { return functions->end(); }
+ PoolList<InlineComponent>::Iterator inlineComponentsBegin() const { return inlineComponents->begin(); }
+ PoolList<InlineComponent>::Iterator inlineComponentsEnd() const { return inlineComponents->end(); }
// If set, then declarations for this object (and init bindings for these) should go into the
// specified object. Used for declarations inside group properties.
@@ -358,6 +368,7 @@ public:
QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
QString appendAlias(Alias *prop, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
void appendFunction(QmlIR::Function *f);
+ void appendInlineComponent(InlineComponent *ic);
QString appendBinding(Binding *b, bool isListBinding);
Binding *findBinding(quint32 nameIndex) const;
@@ -381,6 +392,7 @@ private:
PoolList<Signal> *qmlSignals;
PoolList<Binding> *bindings;
PoolList<Function> *functions;
+ PoolList<InlineComponent> *inlineComponents;
};
struct Q_QMLCOMPILER_PRIVATE_EXPORT Pragma
@@ -409,6 +421,9 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT Document
int registerString(const QString &str) { return jsGenerator.registerString(str); }
QString stringAt(int index) const { return jsGenerator.stringForIndex(index); }
+
+ int objectCount() const {return objects.size();}
+ Object* objectAt(int i) const {return objects.at(i);}
};
class Q_QMLCOMPILER_PRIVATE_EXPORT ScriptDirectivesCollector : public QQmlJS::Directives
@@ -449,6 +464,7 @@ public:
bool visit(QQmlJS::AST::UiArrayBinding *ast) override;
bool visit(QQmlJS::AST::UiObjectBinding *ast) override;
bool visit(QQmlJS::AST::UiObjectDefinition *ast) override;
+ bool visit(QQmlJS::AST::UiInlineComponent *ast) override;
bool visit(QQmlJS::AST::UiEnumDeclaration *ast) override;
bool visit(QQmlJS::AST::UiPublicMember *ast) override;
bool visit(QQmlJS::AST::UiScriptBinding *ast) override;
@@ -527,6 +543,8 @@ public:
QQmlJS::MemoryPool *pool;
QString sourceCode;
QV4::Compiler::JSUnitGenerator *jsGenerator;
+
+ bool insideInlineComponent = false;
};
struct Q_QMLCOMPILER_PRIVATE_EXPORT QmlUnitGenerator
diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp
index 6532576e03..58b8ea2c4f 100644
--- a/src/qml/debugger/qqmldebug.cpp
+++ b/src/qml/debugger/qqmldebug.cpp
@@ -65,8 +65,7 @@ QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
*/
QStringList QQmlDebuggingEnabler::debuggerServices()
{
- return QStringList() << QV4DebugService::s_key << QQmlEngineDebugService::s_key
- << QDebugMessageService::s_key;
+ return {QV4DebugService::s_key, QQmlEngineDebugService::s_key, QDebugMessageService::s_key};
}
/*!
@@ -76,7 +75,7 @@ QStringList QQmlDebuggingEnabler::debuggerServices()
*/
QStringList QQmlDebuggingEnabler::inspectorServices()
{
- return QStringList() << QQmlInspectorService::s_key;
+ return {QQmlInspectorService::s_key};
}
/*!
@@ -87,8 +86,7 @@ QStringList QQmlDebuggingEnabler::inspectorServices()
*/
QStringList QQmlDebuggingEnabler::profilerServices()
{
- return QStringList() << QQmlProfilerService::s_key << QQmlEngineControlService::s_key
- << QDebugMessageService::s_key;
+ return {QQmlProfilerService::s_key, QQmlEngineControlService::s_key, QDebugMessageService::s_key};
}
/*!
@@ -99,7 +97,7 @@ QStringList QQmlDebuggingEnabler::profilerServices()
*/
QStringList QQmlDebuggingEnabler::nativeDebuggerServices()
{
- return QStringList() << QQmlNativeDebugService::s_key;
+ return {QQmlNativeDebugService::s_key};
}
/*!
diff --git a/src/qml/inlinecomponentutils_p.h b/src/qml/inlinecomponentutils_p.h
new file mode 100644
index 0000000000..99b28349cd
--- /dev/null
+++ b/src/qml/inlinecomponentutils_p.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef INLINECOMPONENTUTILS_P_H
+#define INLINECOMPONENTUTILS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qv4compileddata_p.h>
+#include <private/qv4executablecompilationunit_p.h>
+
+namespace icutils {
+struct Node {
+ Node() = default;
+ Node(const Node &) = default;
+ Node(Node &&) = default;
+ Node& operator=(Node const &) = default;
+ Node& operator=(Node &&) = default;
+ bool operator==(Node const &other) const {return index == other.index;}
+
+ Node(std::vector<QV4::CompiledData::InlineComponent>::size_type s) {
+ index = quint32(s);
+ temporaryMark = 0;
+ permanentMark = 0;
+ }
+
+ union {
+ quint32_le_bitfield<0, 30> index;
+ quint32_le_bitfield<30, 1> temporaryMark;
+ quint32_le_bitfield<31, 1> permanentMark;
+ };
+};
+
+using AdjacencyList = std::vector<std::vector<Node*>>;
+
+template<typename ObjectContainer, typename InlineComponent>
+void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer, AdjacencyList &adjacencyList, std::vector<Node> &nodes, const std::vector<InlineComponent> &allICs) {
+ using CompiledObject = typename ObjectContainer::CompiledObject;
+ // add an edge from A to B if A and B are inline components with the same containing type
+ // and A inherits from B (ignore indirect chains through external types for now)
+ // or if A instantiates B
+ for (typename std::vector<InlineComponent>::size_type i = 0; i < allICs.size(); ++i) {
+ const auto& ic = allICs[i];
+ const CompiledObject *obj = objectContainer->objectAt(ic.objectIndex);
+ QV4::ResolvedTypeReference *currentICTypeRef = objectContainer->resolvedType(ic.nameIndex);
+ auto createEdgeFromTypeRef = [&](QV4::ResolvedTypeReference *targetTypeRef) {
+ if (targetTypeRef && targetTypeRef->type.isInlineComponentType()) {
+ if (targetTypeRef->type.containingType() == currentICTypeRef->type.containingType()) {
+ auto icIt = std::find_if(allICs.cbegin(), allICs.cend(), [&](const QV4::CompiledData::InlineComponent &icSearched){
+ return int(icSearched.objectIndex) == targetTypeRef->type.inlineComponentObjectId();
+ });
+ Q_ASSERT(icIt != allICs.cend());
+ Node& target = nodes[i];
+ adjacencyList[std::distance(allICs.cbegin(), icIt)].push_back(&target);
+ }
+ }
+ };
+ if (obj->inheritedTypeNameIndex != 0) {
+ QV4::ResolvedTypeReference *parentTypeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
+ createEdgeFromTypeRef(parentTypeRef);
+
+ }
+ auto referencedInICObjectIndex = ic.objectIndex + 1;
+ while (int(referencedInICObjectIndex) < objectContainer->objectCount()) {
+ auto potentiallyReferencedInICObject = objectContainer->objectAt(referencedInICObjectIndex);
+ bool stillInIC = !(potentiallyReferencedInICObject-> flags & QV4::CompiledData::Object::IsInlineComponentRoot)
+ && (potentiallyReferencedInICObject-> flags & QV4::CompiledData::Object::InPartOfInlineComponent);
+ if (!stillInIC)
+ break;
+ createEdgeFromTypeRef(objectContainer->resolvedType(potentiallyReferencedInICObject->inheritedTypeNameIndex));
+ ++referencedInICObjectIndex;
+ }
+ }
+};
+
+inline void topoVisit(Node *node, AdjacencyList &adjacencyList, bool &hasCycle, std::vector<Node> &nodesSorted) {
+ if (node->permanentMark)
+ return;
+ if (node->temporaryMark) {
+ hasCycle = true;
+ return;
+ }
+ node->temporaryMark = 1;
+
+ auto const &edges = adjacencyList[node->index];
+ for (auto edgeTarget =edges.begin(); edgeTarget != edges.end(); ++edgeTarget) {
+ topoVisit(*edgeTarget, adjacencyList, hasCycle, nodesSorted);
+ }
+
+ node->temporaryMark = 0;
+ node->permanentMark = 1;
+ nodesSorted.push_back(*node);
+};
+
+// Use DFS based topological sorting (https://en.wikipedia.org/wiki/Topological_sorting)
+inline std::vector<Node> topoSort(std::vector<Node> &nodes, AdjacencyList &adjacencyList, bool &hasCycle) {
+ std::vector<Node> nodesSorted;
+ nodesSorted.reserve(nodes.size());
+
+ hasCycle = false;
+ auto currentNodeIt = std::find_if(nodes.begin(), nodes.end(), [](const Node& node) {
+ return node.permanentMark == 0;
+ });
+ // Do a topological sort of all inline components
+ // afterwards, nodesSorted contains the nodes for the inline components in reverse topological order
+ while (currentNodeIt != nodes.end() && !hasCycle) {
+ Node& currentNode = *currentNodeIt;
+ topoVisit(&currentNode, adjacencyList, hasCycle, nodesSorted);
+ currentNodeIt = std::find_if(nodes.begin(), nodes.end(), [](const Node& node) {
+ return node.permanentMark == 0;
+ });
+ }
+ return nodesSorted;
+}
+}
+
+#endif // INLINECOMPONENTUTILS_P_H
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index 065fbc1c0a..6946a64d11 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -71,11 +71,6 @@
#include <private/qqmlglobal_p.h>
#include <qqmlengine.h>
-#undef Q_D
-#undef Q_Q
-#define Q_D(blah)
-#define Q_Q(blah)
-
Q_DECLARE_METATYPE(QList<int>)
/*!
@@ -257,7 +252,7 @@ Q_DECLARE_METATYPE(QList<int>)
\l installExtensions().
\value TranslationExtension Indicates that translation functions (\c qsTr(),
- for example) should be installed.
+ for example) should be installed. This also installs the Qt.uiLanguage property.
\value ConsoleExtension Indicates that console functions (\c console.log(),
for example) should be installed.
@@ -692,7 +687,6 @@ QJSValue QJSEngine::newArray(uint length)
*/
QJSValue QJSEngine::newQObject(QObject *object)
{
- Q_D(QJSEngine);
QV4::ExecutionEngine *v4 = m_v4Engine;
QV4::Scope scope(v4);
if (object) {
@@ -719,7 +713,6 @@ QJSValue QJSEngine::newQObject(QObject *object)
*/
QJSValue QJSEngine::newQMetaObject(const QMetaObject* metaObject) {
- Q_D(QJSEngine);
QV4::ExecutionEngine *v4 = m_v4Engine;
QV4::Scope scope(v4);
QV4::ScopedValue v(scope, QV4::QMetaObjectWrapper::create(v4, metaObject));
@@ -1004,6 +997,35 @@ void QJSEngine::throwError(QJSValue::ErrorType errorType, const QString &message
m_v4Engine->throwError(e);
}
+/*!
+ \property QJSEngine::uiLanguage
+ \brief the language to be used for translating user interface strings
+ \since 5.15
+
+ This property holds the name of the language to be used for user interface
+ string translations. It is exposed for reading and writing as \c{Qt.uiLanguage} when
+ the QJSEngine::TranslationExtension is installed on the engine. It is always exposed
+ in instances of QQmlEngine.
+
+ You can set the value freely and use it in bindings. It is recommended to set it
+ after installing translators in your application. By convention, an empty string
+ means no translation from the language used in the source code is intended to occur.
+*/
+void QJSEngine::setUiLanguage(const QString &language)
+{
+ Q_D(QJSEngine);
+ if (language == d->uiLanguage)
+ return;
+ d->uiLanguage = language;
+ emit uiLanguageChanged();
+}
+
+QString QJSEngine::uiLanguage() const
+{
+ Q_D(const QJSEngine);
+ return d->uiLanguage;
+}
+
QJSEnginePrivate *QJSEnginePrivate::get(QV4::ExecutionEngine *e)
{
return e->jsEngine()->d_func();
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h
index 31a4d68baa..31229e1f20 100644
--- a/src/qml/jsapi/qjsengine.h
+++ b/src/qml/jsapi/qjsengine.h
@@ -60,6 +60,7 @@ class Q_QML_EXPORT QJSEngine
: public QObject
{
Q_OBJECT
+ Q_PROPERTY(QString uiLanguage READ uiLanguage WRITE setUiLanguage NOTIFY uiLanguageChanged)
public:
QJSEngine();
explicit QJSEngine(QObject *parent);
@@ -121,6 +122,12 @@ public:
void throwError(const QString &message);
void throwError(QJSValue::ErrorType errorType, const QString &message = QString());
+ QString uiLanguage() const;
+ void setUiLanguage(const QString &language);
+
+Q_SIGNALS:
+ void uiLanguageChanged();
+
private:
QJSValue create(int type, const void *ptr);
diff --git a/src/qml/jsapi/qjsengine_p.h b/src/qml/jsapi/qjsengine_p.h
index 164a70d000..7866a5bdda 100644
--- a/src/qml/jsapi/qjsengine_p.h
+++ b/src/qml/jsapi/qjsengine_p.h
@@ -107,6 +107,7 @@ public:
// Shared by QQmlEngine
mutable QRecursiveMutex mutex;
+ QString uiLanguage;
// These methods may be called from the QML loader thread
inline QQmlPropertyCache *cache(QObject *obj, int minorVersion = -1);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index dcdebfb398..86e178d568 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1949,11 +1949,12 @@ void ExecutionEngine::initQmlGlobalObject()
void ExecutionEngine::initializeGlobal()
{
QV4::Scope scope(this);
- QV4::GlobalExtensions::init(globalObject, QJSEngine::AllExtensions);
QV4::ScopedObject qt(scope, memoryManager->allocate<QV4::QtObject>(qmlEngine()));
globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt);
+ QV4::GlobalExtensions::init(globalObject, QJSEngine::AllExtensions);
+
#if QT_CONFIG(qml_locale)
QQmlLocale::registerStringLocaleCompare(this);
QQmlDateExtension::registerExtension(this);
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index b1e2879bba..fa4a1f1ce4 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -53,6 +53,7 @@
#include <private/qv4compilationunitmapper_p.h>
#include <private/qml_compile_hash_p.h>
#include <private/qqmltypewrapper_p.h>
+#include <private/inlinecomponentutils_p.h>
#include <QtQml/qqmlfile.h>
#include <QtQml/qqmlpropertymap.h>
@@ -62,6 +63,7 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qscopeguard.h>
#include <QtCore/qcryptographichash.h>
+#include <QtCore/QScopedValueRollback>
#if defined(QML_COMPILE_HASH)
# ifdef Q_OS_LINUX
@@ -387,7 +389,7 @@ IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int com
return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache);
}
-void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine, QQmlMetaType::CompositeMetaTypeIds typeIds)
+void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine, CompositeMetaTypeIds typeIds)
{
this->qmlEngine = qmlEngine;
@@ -399,6 +401,7 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi
metaTypeId = typeIds.id;
listMetaTypeId = typeIds.listId;
qmlEngine->registerInternalCompositeType(this);
+
} else {
const QV4::CompiledData::Object *obj = objectAt(/*root object*/0);
auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex);
@@ -413,29 +416,105 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi
}
// Collect some data for instantiation later.
+ using namespace icutils;
+ std::vector<QV4::CompiledData::InlineComponent> allICs {};
+ for (int i=0; i != objectCount(); ++i) {
+ const CompiledObject *obj = objectAt(i);
+ for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
+ allICs.push_back(*it);
+ }
+ }
+ std::vector<Node> nodes;
+ nodes.resize(allICs.size());
+ std::iota(nodes.begin(), nodes.end(), 0);
+ AdjacencyList adjacencyList;
+ adjacencyList.resize(nodes.size());
+ fillAdjacencyListForInlineComponents(this, adjacencyList, nodes, allICs);
+ bool hasCycle = false;
+ auto nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
+ Q_ASSERT(!hasCycle); // would have already been discovered by qqmlpropertycachcecreator
+
+ // We need to first iterate over all inline components, as the containing component might create instances of them
+ // and in that case we need to add its object count
+ for (auto nodeIt = nodesSorted.rbegin(); nodeIt != nodesSorted.rend(); ++nodeIt) {
+ const auto &ic = allICs.at(nodeIt->index);
+ int lastICRoot = ic.objectIndex;
+ for (int i = ic.objectIndex; i<objectCount(); ++i) {
+ const QV4::CompiledData::Object *obj = objectAt(i);
+ bool leftCurrentInlineComponent =
+ (i != lastICRoot && obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
+ || !(obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent);
+ if (leftCurrentInlineComponent)
+ break;
+ inlineComponentData[lastICRoot].totalBindingCount += obj->nBindings;
+
+ if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
+ if (typeRef->type.isValid() && typeRef->type.parserStatusCast() != -1)
+ ++inlineComponentData[lastICRoot].totalParserStatusCount;
+
+ ++inlineComponentData[lastICRoot].totalObjectCount;
+ if (typeRef->compilationUnit) {
+ // if the type is an inline component type, we have to extract the information from it
+ // This requires that inline components are visited in the correct order
+ auto icRoot = typeRef->compilationUnit->icRoot;
+ if (typeRef->type.isInlineComponentType()) {
+ icRoot = typeRef->type.inlineComponendId();
+ }
+ QScopedValueRollback<int> rollback {typeRef->compilationUnit->icRoot, icRoot};
+ inlineComponentData[lastICRoot].totalBindingCount += typeRef->compilationUnit->totalBindingsCount();
+ inlineComponentData[lastICRoot].totalParserStatusCount += typeRef->compilationUnit->totalParserStatusCount();
+ inlineComponentData[lastICRoot].totalObjectCount += typeRef->compilationUnit->totalObjectCount();
+ }
+ }
+ }
+ }
int bindingCount = 0;
int parserStatusCount = 0;
int objectCount = 0;
for (quint32 i = 0, count = this->objectCount(); i < count; ++i) {
const QV4::CompiledData::Object *obj = objectAt(i);
+ if (obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent) {
+ continue;
+ }
bindingCount += obj->nBindings;
if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
- if (typeRef->type.isValid()) {
- if (typeRef->type.parserStatusCast() != -1)
- ++parserStatusCount;
- }
+ if (typeRef->type.isValid() && typeRef->type.parserStatusCast() != -1)
+ ++parserStatusCount;
++objectCount;
if (typeRef->compilationUnit) {
- bindingCount += typeRef->compilationUnit->totalBindingsCount;
- parserStatusCount += typeRef->compilationUnit->totalParserStatusCount;
- objectCount += typeRef->compilationUnit->totalObjectCount;
+ auto icRoot = typeRef->compilationUnit->icRoot;
+ if (typeRef->type.isInlineComponentType()) {
+ icRoot = typeRef->type.inlineComponendId();
+ }
+ QScopedValueRollback<int> rollback {typeRef->compilationUnit->icRoot, icRoot};
+ bindingCount += typeRef->compilationUnit->totalBindingsCount();
+ parserStatusCount += typeRef->compilationUnit->totalParserStatusCount();
+ objectCount += typeRef->compilationUnit->totalObjectCount();
}
}
}
- totalBindingsCount = bindingCount;
- totalParserStatusCount = parserStatusCount;
- totalObjectCount = objectCount;
+ m_totalBindingsCount = bindingCount;
+ m_totalParserStatusCount = parserStatusCount;
+ m_totalObjectCount = objectCount;
+}
+
+int ExecutableCompilationUnit::totalBindingsCount() const {
+ if (icRoot == -1)
+ return m_totalBindingsCount;
+ return inlineComponentData[icRoot].totalBindingCount;
+}
+
+int ExecutableCompilationUnit::totalObjectCount() const {
+ if (icRoot == -1)
+ return m_totalObjectCount;
+ return inlineComponentData[icRoot].totalObjectCount;
+}
+
+int ExecutableCompilationUnit::totalParserStatusCount() const {
+ if (icRoot == -1)
+ return m_totalParserStatusCount;
+ return inlineComponentData[icRoot].totalParserStatusCount;
}
bool ExecutableCompilationUnit::verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const
@@ -453,6 +532,13 @@ bool ExecutableCompilationUnit::verifyChecksum(const CompiledData::DependentType
sizeof(data->dependencyMD5Checksum)) == 0;
}
+CompositeMetaTypeIds ExecutableCompilationUnit::typeIdsForComponent(int objectid) const
+{
+ if (objectid == 0)
+ return {metaTypeId, listMetaTypeId};
+ return inlineComponentData[objectid].typeIds;
+}
+
QStringList ExecutableCompilationUnit::moduleRequests() const
{
QStringList requests;
@@ -734,13 +820,14 @@ QQmlRefPointer<QQmlPropertyCache> ResolvedTypeReference::createPropertyCache(QQm
typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject(), minorVersion);
return typePropertyCache;
} else {
+ Q_ASSERT(compilationUnit);
return compilationUnit->rootPropertyCache();
}
}
bool ResolvedTypeReference::addToHash(QCryptographicHash *hash, QQmlEngine *engine)
{
- if (type.isValid()) {
+ if (type.isValid() && !type.isInlineComponentType()) {
bool ok = false;
hash->addData(createPropertyCache(engine)->checksum(&ok));
return ok;
diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h
index 1272e7a2c3..8cad18a3dc 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit_p.h
+++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h
@@ -64,6 +64,26 @@ QT_BEGIN_NAMESPACE
class QQmlScriptData;
class QQmlEnginePrivate;
+
+struct InlineComponentData {
+
+ InlineComponentData() = default;
+ InlineComponentData(const CompositeMetaTypeIds &typeIds, int objectIndex, int nameIndex, int totalObjectCount, int totalBindingCount, int totalParserStatusCount)
+ : typeIds(typeIds)
+ , objectIndex(objectIndex)
+ , nameIndex(nameIndex)
+ , totalObjectCount(totalObjectCount)
+ , totalBindingCount(totalBindingCount)
+ , totalParserStatusCount(totalParserStatusCount) {}
+
+ CompositeMetaTypeIds typeIds;
+ int objectIndex = -1;
+ int nameIndex = -1;
+ int totalObjectCount = 0;
+ int totalBindingCount = 0;
+ int totalParserStatusCount = 0;
+};
+
namespace QV4 {
// index is per-object binding index
@@ -143,11 +163,16 @@ public:
QHash<int, IdentifierHash> namedObjectsPerComponentCache;
inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex);
- void finalizeCompositeType(QQmlEnginePrivate *qmlEngine, QQmlMetaType::CompositeMetaTypeIds typeIds);
+ void finalizeCompositeType(QQmlEnginePrivate *qmlEngine, CompositeMetaTypeIds typeIdsForComponent);
- int totalBindingsCount = 0; // Number of bindings used in this type
- int totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
- int totalObjectCount = 0; // Number of objects explicitly instantiated
+ int m_totalBindingsCount = 0; // Number of bindings used in this type
+ int m_totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses
+ int m_totalObjectCount = 0; // Number of objects explicitly instantiated
+ int icRoot = -1;
+
+ int totalBindingsCount() const;
+ int totalParserStatusCount() const;
+ int totalObjectCount() const;
QVector<QQmlRefPointer<QQmlScriptData>> dependentScripts;
ResolvedTypeReferenceMap resolvedTypes;
@@ -155,12 +180,14 @@ public:
bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const;
- QQmlMetaType::CompositeMetaTypeIds typeIds() const { return {metaTypeId, listMetaTypeId}; }
+ CompositeMetaTypeIds typeIdsForComponent(int objectid = 0) const;
int metaTypeId = -1;
int listMetaTypeId = -1;
bool isRegisteredWithEngine = false;
+ QHash<int, InlineComponentData> inlineComponentData;
+
QScopedPointer<CompilationUnitMapper> backingFile;
// --- interface for QQmlPropertyCacheCreator
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 6fbb9df164..397c0b51a5 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -91,6 +91,7 @@
%token T_EXPORT "export"
%token T_FROM "from"
%token T_REQUIRED "required"
+%token T_COMPONENT "component"
--- template strings
%token T_NO_SUBSTITUTION_TEMPLATE"(no subst template)"
@@ -123,7 +124,7 @@
%token T_FOR_LOOKAHEAD_OK "(for lookahead ok)"
--%left T_PLUS T_MINUS
-%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY T_ON T_SET T_GET T_OF T_STATIC T_FROM T_AS T_REQUIRED
+%nonassoc T_IDENTIFIER T_COLON T_SIGNAL T_PROPERTY T_READONLY T_ON T_SET T_GET T_OF T_STATIC T_FROM T_AS T_REQUIRED T_COMPONENT
%nonassoc REDUCE_HERE
%right T_THEN T_ELSE
%right T_WITHOUTAS T_AS
@@ -1426,6 +1427,19 @@ UiObjectMember: T_ENUM T_IDENTIFIER T_LBRACE EnumMemberList T_RBRACE;
}
./
+UiObjectMember: T_COMPONENT T_IDENTIFIER T_COLON UiObjectDefinition;
+/.
+ case $rule_number: {
+ if (!stringRef(2).front().isUpper()) {
+ diagnostic_messages.append(compileError(loc(2),
+ QLatin1String("Type name must be upper case"), QtWarningMsg));
+ }
+ auto inlineComponent = new (pool) AST::UiInlineComponent(stringRef(2), sym(4).UiObjectDefinition);
+ inlineComponent->componentToken = loc(1);
+ sym(1).Node = inlineComponent;
+ } break;
+./
+
EnumMemberList: T_IDENTIFIER;
/.
case $rule_number: {
@@ -1468,29 +1482,31 @@ EnumMemberList: EnumMemberList T_COMMA T_IDENTIFIER T_EQ T_NUMERIC_LITERAL;
}
./
-QmlIdentifier: T_IDENTIFIER;
-QmlIdentifier: T_PROPERTY;
-QmlIdentifier: T_SIGNAL;
-QmlIdentifier: T_READONLY;
-QmlIdentifier: T_ON;
-QmlIdentifier: T_GET;
-QmlIdentifier: T_SET;
-QmlIdentifier: T_FROM;
-QmlIdentifier: T_OF;
-QmlIdentifier: T_REQUIRED;
-
-JsIdentifier: T_IDENTIFIER;
-JsIdentifier: T_PROPERTY;
-JsIdentifier: T_SIGNAL;
-JsIdentifier: T_READONLY;
-JsIdentifier: T_ON;
-JsIdentifier: T_GET;
-JsIdentifier: T_SET;
-JsIdentifier: T_FROM;
-JsIdentifier: T_STATIC;
-JsIdentifier: T_OF;
-JsIdentifier: T_AS;
-JsIdentifier: T_REQUIRED;
+QmlIdentifier: T_IDENTIFIER
+ | T_PROPERTY
+ | T_SIGNAL
+ | T_READONLY
+ | T_ON
+ | T_GET
+ | T_SET
+ | T_FROM
+ | T_OF
+ | T_REQUIRED
+ | T_COMPONENT;
+
+JsIdentifier: T_IDENTIFIER
+ | T_PROPERTY
+ | T_SIGNAL
+ | T_READONLY
+ | T_ON
+ | T_GET
+ | T_SET
+ | T_FROM
+ | T_STATIC
+ | T_OF
+ | T_AS
+ | T_REQUIRED
+ | T_COMPONENT;
IdentifierReference: JsIdentifier;
BindingIdentifier: IdentifierReference;
diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp
index 03355b3e38..aa3e8ab5e3 100644
--- a/src/qml/parser/qqmljsast.cpp
+++ b/src/qml/parser/qqmljsast.cpp
@@ -1545,6 +1545,15 @@ void Type::toString(QString *out) const
};
}
+void UiInlineComponent::accept0(Visitor *visitor)
+{
+ if (visitor->visit(this)) {
+ accept(component, visitor);
+ }
+
+ visitor->endVisit(this);
+}
+
} } // namespace QQmlJS::AST
QT_END_NAMESPACE
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index aa355fed85..48a994cd33 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -244,6 +244,7 @@ public:
Kind_UiImport,
Kind_UiObjectBinding,
Kind_UiObjectDefinition,
+ Kind_UiInlineComponent,
Kind_UiObjectInitializer,
Kind_UiObjectMemberList,
Kind_UiArrayMemberList,
@@ -3377,6 +3378,28 @@ public:
UiObjectInitializer *initializer;
};
+class QML_PARSER_EXPORT UiInlineComponent: public UiObjectMember
+{
+public:
+ QQMLJS_DECLARE_AST_NODE(UiInlineComponent)
+
+ UiInlineComponent(const QStringRef& inlineComponentName, UiObjectDefinition* inlineComponent)
+ : name(inlineComponentName), component(inlineComponent)
+ { kind = K; }
+
+ QStringRef name;
+ UiObjectDefinition* component;
+ SourceLocation componentToken;
+
+ SourceLocation lastSourceLocation() const override
+ {return component->lastSourceLocation();}
+
+ SourceLocation firstSourceLocation() const override
+ {return componentToken;}
+
+ void accept0(Visitor *visitor) override;
+};
+
class QML_PARSER_EXPORT UiSourceElement: public UiObjectMember
{
public:
diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h
index 05226fd043..8a8ee2dfae 100644
--- a/src/qml/parser/qqmljsastfwd_p.h
+++ b/src/qml/parser/qqmljsastfwd_p.h
@@ -169,6 +169,7 @@ class UiImport;
class UiPublicMember;
class UiParameterList;
class UiObjectDefinition;
+class UiInlineComponent;
class UiObjectInitializer;
class UiObjectBinding;
class UiScriptBinding;
diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h
index 7146cd00ac..d6b92990ad 100644
--- a/src/qml/parser/qqmljsastvisitor_p.h
+++ b/src/qml/parser/qqmljsastvisitor_p.h
@@ -112,6 +112,7 @@ public:
virtual bool visit(UiEnumDeclaration *) { return true; }
virtual bool visit(UiEnumMemberList *) { return true; }
virtual bool visit(UiVersionSpecifier *) { return true; }
+ virtual bool visit(UiInlineComponent *) { return true; }
virtual void endVisit(UiProgram *) {}
virtual void endVisit(UiImport *) {}
@@ -131,6 +132,7 @@ public:
virtual void endVisit(UiEnumDeclaration *) {}
virtual void endVisit(UiEnumMemberList *) { }
virtual void endVisit(UiVersionSpecifier *) {}
+ virtual void endVisit(UiInlineComponent *) {}
// QQmlJS
virtual bool visit(ThisExpression *) { return true; }
diff --git a/src/qml/parser/qqmljskeywords_p.h b/src/qml/parser/qqmljskeywords_p.h
index 3eb054341f..5f08cc4353 100644
--- a/src/qml/parser/qqmljskeywords_p.h
+++ b/src/qml/parser/qqmljskeywords_p.h
@@ -836,6 +836,25 @@ static inline int classify9(const QChar *s, int parseModeFlags) {
}
}
}
+ else if (s[0].unicode() == 'c') {
+ if (s[1].unicode() == 'o') {
+ if (s[2].unicode() == 'm') {
+ if (s[3].unicode() == 'p') {
+ if (s[4].unicode() == 'o') {
+ if (s[5].unicode() == 'n') {
+ if (s[6].unicode() == 'e') {
+ if (s[7].unicode() == 'n') {
+ if (s[8].unicode() == 't') {
+ return (parseModeFlags & Lexer::QmlMode) ? int(Lexer::T_COMPONENT) : int(Lexer::T_IDENTIFIER);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
return Lexer::T_IDENTIFIER;
}
diff --git a/src/qml/qml.pro b/src/qml/qml.pro
index 985f7ca383..5b2ac4b5cf 100644
--- a/src/qml/qml.pro
+++ b/src/qml/qml.pro
@@ -39,6 +39,7 @@ greaterThan(QT_CLANG_MAJOR_VERSION, 3)|greaterThan(QT_CLANG_MINOR_VERSION, 3)| \
WERROR += -Wno-error=unused-const-variable
HEADERS += qtqmlglobal.h \
+ inlinecomponentutils_p.h \
qtqmlglobal_p.h \
qtqmlcompilerglobal.h \
qtqmlcompilerglobal_p.h
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index 7f80fe5e1c..7d961cd0c7 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE
QQmlApplicationEnginePrivate::QQmlApplicationEnginePrivate(QQmlEngine *e)
: QQmlEnginePrivate(e)
{
+ uiLanguage = QLocale().bcp47Name();
}
QQmlApplicationEnginePrivate::~QQmlApplicationEnginePrivate()
@@ -72,6 +73,7 @@ void QQmlApplicationEnginePrivate::init()
&QCoreApplication::quit, Qt::QueuedConnection);
q->connect(q, &QQmlApplicationEngine::exit, QCoreApplication::instance(),
&QCoreApplication::exit, Qt::QueuedConnection);
+ q->connect(q, SIGNAL(uiLanguageChanged()), q_func(), SLOT(_q_loadTranslations()));
#if QT_CONFIG(translation)
QTranslator* qtTranslator = new QTranslator(q);
if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath), QLatin1String(".qm")))
@@ -83,20 +85,27 @@ void QQmlApplicationEnginePrivate::init()
QCoreApplication::instance()->setProperty("__qml_using_qqmlapplicationengine", QVariant(true));
}
-void QQmlApplicationEnginePrivate::loadTranslations(const QUrl &rootFile)
+void QQmlApplicationEnginePrivate::_q_loadTranslations()
{
#if QT_CONFIG(translation)
- if (rootFile.scheme() != QLatin1String("file") && rootFile.scheme() != QLatin1String("qrc"))
+ if (translationsDirectory.isEmpty())
return;
- QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(rootFile));
-
Q_Q(QQmlApplicationEngine);
- QTranslator *translator = new QTranslator(q);
- if (translator->load(QLocale(), QLatin1String("qml"), QLatin1String("_"), fi.path() + QLatin1String("/i18n"), QLatin1String(".qm")))
- QCoreApplication::installTranslator(translator);
- else
- delete translator;
+
+ QScopedPointer<QTranslator> translator(new QTranslator);
+ if (!uiLanguage.isEmpty()) {
+ QLocale locale(uiLanguage);
+ if (translator->load(locale, QLatin1String("qml"), QLatin1String("_"), translationsDirectory, QLatin1String(".qm"))) {
+ if (activeTranslator)
+ QCoreApplication::removeTranslator(activeTranslator.data());
+ QCoreApplication::installTranslator(translator.data());
+ activeTranslator.swap(translator);
+ }
+ } else {
+ activeTranslator.reset();
+ }
+ q->retranslate();
#else
Q_UNUSED(rootFile)
#endif
@@ -106,7 +115,14 @@ void QQmlApplicationEnginePrivate::startLoad(const QUrl &url, const QByteArray &
{
Q_Q(QQmlApplicationEngine);
- loadTranslations(url); //Translations must be loaded before the QML file is
+ if (url.scheme() == QLatin1String("file") || url.scheme() == QLatin1String("qrc")) {
+ QFileInfo fi(QQmlFile::urlToLocalFileOrQrc(url));
+ translationsDirectory = fi.path() + QLatin1String("/i18n");
+ } else {
+ translationsDirectory.clear();
+ }
+
+ _q_loadTranslations(); //Translations must be loaded before the QML file is
QQmlComponent *c = new QQmlComponent(q, q);
if (dataFlag)
@@ -181,6 +197,7 @@ void QQmlApplicationEnginePrivate::finishLoad(QQmlComponent *c)
\list
\li Translation files must have "qml_" prefix e.g. qml_ja_JP.qm.
\endlist
+ \li Translations are reloaded when the \c QJSEngine::uiLanguage / \c Qt.uiLanguage property is changed.
\li Automatically sets an incubation controller if the scene contains a QQuickWindow.
\li Automatically sets a \c QQmlFileSelector as the url interceptor, applying file selectors to all
QML files and assets.
diff --git a/src/qml/qml/qqmlapplicationengine.h b/src/qml/qml/qqmlapplicationengine.h
index 2b4de91154..37f75d5068 100644
--- a/src/qml/qml/qqmlapplicationengine.h
+++ b/src/qml/qml/qqmlapplicationengine.h
@@ -74,6 +74,7 @@ Q_SIGNALS:
private:
Q_DISABLE_COPY(QQmlApplicationEngine)
+ Q_PRIVATE_SLOT(d_func(), void _q_loadTranslations())
Q_DECLARE_PRIVATE(QQmlApplicationEngine)
};
diff --git a/src/qml/qml/qqmlapplicationengine_p.h b/src/qml/qml/qqmlapplicationengine_p.h
index 1279e400e8..c514e3daf9 100644
--- a/src/qml/qml/qqmlapplicationengine_p.h
+++ b/src/qml/qml/qqmlapplicationengine_p.h
@@ -70,10 +70,12 @@ public:
void cleanUp();
void startLoad(const QUrl &url, const QByteArray &data = QByteArray(), bool dataFlag = false);
- void loadTranslations(const QUrl &rootFile);
+ void _q_loadTranslations();
void finishLoad(QQmlComponent *component);
QList<QObject *> objects;
QVariantMap initialProperties;
+ QString translationsDirectory;
+ QScopedPointer<QTranslator> activeTranslator;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 9b6f83f144..915dc5b242 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -1307,6 +1307,21 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
}
/*!
+ \qmlproperty string Qt::uiLanguage
+ \since 5.15
+
+ The uiLanguage holds the name of the language to be used for user interface
+ string translations. It is exposed in C++ as QQmlEngine::uiLanguage property.
+
+ You can set the value freely and use it in bindings. It is recommended to set it
+ after installing translators in your application. By convention, an empty string
+ means no translation from the language used in the source code is intended to occur.
+
+ If you're using QQmlApplicationEngine and the value changes, QQmlEngine::retranslate()
+ will be called.
+*/
+
+/*!
\fn template<typename T> T QQmlEngine::singletonInstance(int qmlTypeId)
Returns the instance of a singleton type that was registered under \a qmlTypeId.
@@ -2339,12 +2354,23 @@ int QQmlEnginePrivate::listType(int t) const
return QQmlMetaType::listType(t);
}
+
+static QQmlPropertyCache *propertyCacheForPotentialInlineComponentType(int t, const QHash<int, QV4::ExecutableCompilationUnit *>::const_iterator &iter) {
+ if (t != (*iter)->metaTypeId) {
+ // this is an inline component, and what we have in the iterator is currently the parent compilation unit
+ for (auto &&icDatum: (*iter)->inlineComponentData)
+ if (icDatum.typeIds.id == t)
+ return (*iter)->propertyCaches.at(icDatum.objectIndex);
+ }
+ return (*iter)->rootPropertyCache().data();
+}
+
QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
{
Locker locker(this);
auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return QQmlMetaObject((*iter)->rootPropertyCache().data());
+ return propertyCacheForPotentialInlineComponentType(t, iter);
} else {
QQmlType type = QQmlMetaType::qmlType(t);
return QQmlMetaObject(type.baseMetaObject());
@@ -2356,7 +2382,7 @@ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
Locker locker(this);
auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return QQmlMetaObject((*iter)->rootPropertyCache().data());
+ return propertyCacheForPotentialInlineComponentType(t, iter);
} else {
QQmlType type = QQmlMetaType::qmlType(t);
return QQmlMetaObject(type.metaObject());
@@ -2368,7 +2394,7 @@ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
Locker locker(this);
auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return (*iter)->rootPropertyCache().data();
+ return propertyCacheForPotentialInlineComponentType(t, iter);
} else {
QQmlType type = QQmlMetaType::qmlType(t);
locker.unlock();
@@ -2381,7 +2407,7 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t, int minorVe
Locker locker(this);
auto iter = m_compositeTypes.constFind(t);
if (iter != m_compositeTypes.cend()) {
- return (*iter)->rootPropertyCache().data();
+ return propertyCacheForPotentialInlineComponentType(t, iter);
} else {
QQmlType type = QQmlMetaType::qmlType(t);
locker.unlock();
@@ -2401,6 +2427,9 @@ void QQmlEnginePrivate::registerInternalCompositeType(QV4::ExecutableCompilation
// The QQmlCompiledData is not referenced here, but it is removed from this
// hash in the QQmlCompiledData destructor
m_compositeTypes.insert(compilationUnit->metaTypeId, compilationUnit);
+ for (auto &&data: compilationUnit->inlineComponentData) {
+ m_compositeTypes.insert(data.typeIds.id, compilationUnit);
+ }
}
void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit)
@@ -2409,6 +2438,14 @@ void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::ExecutableCompilati
Locker locker(this);
m_compositeTypes.remove(compilationUnit->metaTypeId);
+ for (auto&& icDatum: compilationUnit->inlineComponentData)
+ m_compositeTypes.remove(icDatum.typeIds.id);
+}
+
+QV4::ExecutableCompilationUnit *QQmlEnginePrivate::obtainExecutableCompilationUnit(int typeId)
+{
+ Locker locker(this);
+ return m_compositeTypes.value(typeId, nullptr);
}
template<>
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 98c7823921..33fa800ff4 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -231,6 +231,7 @@ public:
QQmlPropertyCache *rawPropertyCacheForType(int, int minorVersion = -1);
void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit);
+ QV4::ExecutableCompilationUnit *obtainExecutableCompilationUnit(int typeId);
bool isTypeLoaded(const QUrl &url) const;
bool isScriptLoaded(const QUrl &url) const;
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 7da0685872..80eafdf146 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -58,6 +58,7 @@
#include <private/qqmltypeloaderqmldircontent_p.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonarray.h>
+#include <QtQml/private/qqmltype_p_p.h>
#include <algorithm>
#include <functional>
@@ -613,6 +614,8 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE/URL-SINGLETON";
else if (type_return->isComposite())
RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE/URL";
+ else if (type_return->isInlineComponentType())
+ RESOLVE_TYPE_DEBUG << type_return->typeName() << ' ' << type_return->sourceUrl() << " TYPE(INLINECOMPONENT)";
else
RESOLVE_TYPE_DEBUG << type_return->typeName() << " TYPE";
}
@@ -709,6 +712,37 @@ bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader, const QHashedSt
}
const QString typeStr = type.toString();
+ if (isInlineComponent) {
+ Q_ASSERT(type_return);
+ bool ret = uri == typeStr;
+ if (ret) {
+ Q_ASSERT(!type_return->isValid());
+ auto createICType = [&]() {
+ auto typePriv = new QQmlTypePrivate {QQmlType::RegistrationType::InlineComponentType};
+ bool ok = false;
+ typePriv->extraData.id->objectId = QUrl(this->url).fragment().toInt(&ok);
+ Q_ASSERT(ok);
+ typePriv->extraData.id->url = QUrl(this->url);
+ auto icType = QQmlType(typePriv);
+ return icType;
+ };
+ if (containingType.isValid()) {
+ // we currently cannot reference a Singleton inside itself
+ // in that case, containingType is still invalid
+ if (int icID = containingType.lookupInlineComponentIdByName(typeStr) != -1) {
+ *type_return = containingType.lookupInlineComponentById(icID);
+ } else {
+ auto icType = createICType();
+ int placeholderId = containingType.generatePlaceHolderICId();
+ const_cast<QQmlImportInstance*>(this)->containingType.associateInlineComponent(typeStr, placeholderId, CompositeMetaTypeIds {}, icType);
+ *type_return = QQmlType(icType);
+ }
+ } else {
+ *type_return = createICType();
+ }
+ }
+ return ret;
+ }
QQmlDirComponents::ConstIterator it = qmlDirComponents.find(typeStr), end = qmlDirComponents.end();
if (it != end) {
QString componentUrl;
@@ -826,47 +860,107 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
QQmlType::RegistrationType registrationType,
bool *typeRecursionDetected)
{
- QQmlImportNamespace *s = nullptr;
- int dot = type.indexOf(Dot);
- if (dot >= 0) {
- QHashedStringRef namespaceName(type.constData(), dot);
- s = findQualifiedNamespace(namespaceName);
- if (!s) {
- if (errors) {
- QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(namespaceName.toString()));
- errors->prepend(error);
- }
- return false;
- }
- int ndot = type.indexOf(Dot,dot+1);
- if (ndot > 0) {
- if (errors) {
- QQmlError error;
- error.setDescription(QQmlImportDatabase::tr("- nested namespaces not allowed"));
- errors->prepend(error);
- }
- return false;
- }
- } else {
- s = &unqualifiedset;
- }
- QHashedStringRef unqualifiedtype = dot < 0 ? type : QHashedStringRef(type.constData()+dot+1, type.length()-dot-1);
- if (s) {
- if (s->resolveType(typeLoader, unqualifiedtype, vmajor, vminor, type_return, &base, errors,
+ const QVector<QHashedStringRef> splitName = type.split(Dot);
+ auto resolveTypeInNamespace = [&](QHashedStringRef unqualifiedtype, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors) -> bool {
+ if (nameSpace->resolveType(typeLoader, unqualifiedtype, vmajor, vminor, type_return, &base, errors,
registrationType, typeRecursionDetected))
return true;
- if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) {
+ if (nameSpace->imports.count() == 1 && !nameSpace->imports.at(0)->isLibrary && type_return && nameSpace != &unqualifiedset) {
// qualified, and only 1 url
*type_return = QQmlMetaType::typeForUrl(
- resolveLocalUrl(s->imports.at(0)->url,
+ resolveLocalUrl(nameSpace->imports.at(0)->url,
unqualifiedtype.toString() + QLatin1String(".qml")),
type, false, errors);
return type_return->isValid();
}
+ return false;
+ };
+ switch (splitName.size()) {
+ case 1: {
+ // must be a simple type
+ return resolveTypeInNamespace(type, &unqualifiedset, errors);
}
-
- return false;
+ case 2: {
+ // either namespace + simple type OR simple type + inline component
+ QQmlImportNamespace *s = findQualifiedNamespace(splitName.at(0));
+ if (s) {
+ // namespace + simple type
+ return resolveTypeInNamespace(splitName.at(1), s, errors);
+ } else {
+ if (resolveTypeInNamespace(splitName.at(0), &unqualifiedset, nullptr)) {
+ // either simple type + inline component
+ auto const icName = splitName.at(1).toString();
+ auto objectIndex = type_return->lookupInlineComponentIdByName(icName);
+ if (objectIndex != -1) {
+ *type_return = type_return->lookupInlineComponentById(objectIndex);
+ } else {
+ auto icTypePriv = new QQmlTypePrivate(QQmlType::RegistrationType::InlineComponentType);
+ icTypePriv->setContainingType(type_return);
+ icTypePriv->extraData.id->url = type_return->sourceUrl();
+ int placeholderId = type_return->generatePlaceHolderICId();
+ icTypePriv->extraData.id->url.setFragment(QString::number(placeholderId));
+ auto icType = QQmlType(icTypePriv);
+ type_return->associateInlineComponent(icName, placeholderId, CompositeMetaTypeIds {}, icType);
+ *type_return = icType;
+ }
+ Q_ASSERT(type_return->containingType().isValid());
+ type_return->setPendingResolutionName(icName);
+ return true;
+ } else {
+ // or a failure
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("- %1 is neither a type nor a namespace").arg(splitName.at(0).toString()));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ }
+ }
+ case 3: {
+ // must be namespace + simple type + inline component
+ QQmlImportNamespace *s = findQualifiedNamespace(splitName.at(0));
+ QQmlError error;
+ if (!s) {
+ error.setDescription(QQmlImportDatabase::tr("- %1 is not a namespace").arg(splitName.at(0).toString()));
+ } else {
+ if (resolveTypeInNamespace(splitName.at(1), s, nullptr)) {
+ auto const icName = splitName.at(2).toString();
+ auto objectIndex = type_return->lookupInlineComponentIdByName(icName);
+ if (objectIndex != -1)
+ *type_return = type_return->lookupInlineComponentById(objectIndex);
+ else {
+ auto icTypePriv = new QQmlTypePrivate(QQmlType::RegistrationType::InlineComponentType);
+ icTypePriv->setContainingType(type_return);
+ icTypePriv->extraData.id->url = type_return->sourceUrl();
+ int placeholderId = type_return->generatePlaceHolderICId();
+ icTypePriv->extraData.id->url.setFragment(QString::number(placeholderId));
+ auto icType = QQmlType(icTypePriv);
+ type_return->associateInlineComponent(icName, placeholderId, CompositeMetaTypeIds {}, icType);
+ *type_return = icType;
+ }
+ type_return->setPendingResolutionName(icName);
+ return true;
+ } else {
+ error.setDescription(QQmlImportDatabase::tr("- %1 is not a type").arg(splitName.at(1).toString()));
+ }
+ }
+ if (errors) {
+ errors->prepend(error);
+ }
+ return false;
+ }
+ default: {
+ // all other numbers suggest a user error
+ if (errors) {
+ QQmlError error;
+ error.setDescription(QQmlImportDatabase::tr("- nested namespaces not allowed"));
+ errors->prepend(error);
+ }
+ return false;
+ }
+ }
+ Q_UNREACHABLE();
}
QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const
@@ -1652,6 +1746,21 @@ bool QQmlImports::addImplicitImport(QQmlImportDatabase *importDb, QList<QQmlErro
}
/*!
+ \internal
+ */
+bool QQmlImports::addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl, QQmlType containingType)
+{
+ importInstance->url = importUrl.toString();
+ importInstance->uri = name;
+ importInstance->isInlineComponent = true;
+ importInstance->majversion = 0;
+ importInstance->minversion = 0;
+ importInstance->containingType = containingType;
+ d->unqualifiedset.imports.push_back(importInstance);
+ return true;
+}
+
+/*!
\internal
Adds information to \a imports such that subsequent calls to resolveType()
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 1f44b22deb..2e994fd27f 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -80,10 +80,12 @@ struct QQmlImportInstance
QString uri; // e.g. QtQuick
QString url; // the base path of the import
QString localDirectoryPath; // the base path of the import if it's a local file
+ QQmlType containingType; // points to the containing type for inline components
int majversion; // the major version imported
int minversion; // the minor version imported
bool isLibrary; // true means that this is not a file import
bool implicitlyImported = false;
+ bool isInlineComponent = false;
QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir
QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir
@@ -151,6 +153,8 @@ public:
bool addImplicitImport(QQmlImportDatabase *importDb, QList<QQmlError> *errors);
+ bool addInlineComponentImport(QQmlImportInstance *const importInstance, const QString &name, const QUrl importUrl, QQmlType containingType);
+
bool addFileImport(QQmlImportDatabase *,
const QString& uri, const QString& prefix, int vmaj, int vmin, bool incomplete,
QList<QQmlError> *errors);
diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp
index 82cad8eba8..b284e44fdf 100644
--- a/src/qml/qml/qqmlirloader.cpp
+++ b/src/qml/qml/qqmlirloader.cpp
@@ -200,6 +200,13 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
object->runtimeFunctionIndices.allocate(pool, functionIndices);
+ const QV4::CompiledData::InlineComponent *serializedInlineComponent = serializedObject->inlineComponentTable();
+ for (uint i = 0; i < serializedObject->nInlineComponents; ++i, ++serializedInlineComponent) {
+ QmlIR::InlineComponent *ic = pool->New<QmlIR::InlineComponent>();
+ *static_cast<QV4::CompiledData::InlineComponent*>(ic) = *serializedInlineComponent;
+ object->inlineComponents->append(ic);
+ }
+
return object;
}
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index f506cdece3..76816618ac 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -531,7 +531,7 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit
return QQmlType(priv);
}
-QQmlMetaType::CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(const QByteArray &className)
+CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(const QByteArray &className)
{
QByteArray ptr = className + '*';
QByteArray lst = "QQmlListProperty<" + className + '>';
@@ -555,7 +555,7 @@ QQmlMetaType::CompositeMetaTypeIds QQmlMetaType::registerInternalCompositeType(c
return {ptr_type, lst_type};
}
-void QQmlMetaType::unregisterInternalCompositeType(const QQmlMetaType::CompositeMetaTypeIds &typeIds)
+void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds)
{
QQmlMetaTypeDataPtr data;
data->qmlLists.remove(typeIds.listId);
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 80126cbffb..037cf89beb 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -63,6 +63,15 @@ class QQmlError;
namespace QV4 { class ExecutableCompilationUnit; }
+struct CompositeMetaTypeIds
+{
+ int id = -1;
+ int listId = -1;
+ CompositeMetaTypeIds() = default;
+ CompositeMetaTypeIds(int id, int listId) : id(id), listId(listId) {}
+ bool isValid() const { return id != -1 && listId != -1; }
+};
+
class Q_QML_PRIVATE_EXPORT QQmlMetaType
{
public:
@@ -80,18 +89,8 @@ public:
static void unregisterType(int type);
- struct CompositeMetaTypeIds
- {
- int id = -1;
- int listId = -1;
- CompositeMetaTypeIds() = default;
- CompositeMetaTypeIds(int id, int listId) : id(id), listId(listId) {}
- bool isValid() const { return id != -1 && listId != -1; }
- };
-
static CompositeMetaTypeIds registerInternalCompositeType(const QByteArray &className);
- static void unregisterInternalCompositeType(const QQmlMetaType::CompositeMetaTypeIds &typeIds);
-
+ static void unregisterInternalCompositeType(const CompositeMetaTypeIds &typeIds);
static void registerModule(const char *uri, int versionMajor, int versionMinor);
static bool protectModule(const QString &uri, int majVersion);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 78df02554c..198ce98f2d 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -62,6 +62,7 @@
#include <QScopedValueRollback>
#include <qtqml_tracepoints_p.h>
+#include <QScopedValueRollback>
QT_USE_NAMESPACE
@@ -77,9 +78,9 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlR
init(parentContext);
sharedState->componentAttached = nullptr;
- sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount);
- sharedState->allParserStatusCallbacks.allocate(compilationUnit->totalParserStatusCount);
- sharedState->allCreatedObjects.allocate(compilationUnit->totalObjectCount);
+ sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount());
+ sharedState->allParserStatusCallbacks.allocate(compilationUnit->totalParserStatusCount());
+ sharedState->allCreatedObjects.allocate(compilationUnit->totalObjectCount());
sharedState->allJavaScriptObjects = nullptr;
sharedState->creationContext = creationContext;
sharedState->rootContext = nullptr;
@@ -87,7 +88,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlR
if (auto profiler = QQmlEnginePrivate::get(engine)->profiler) {
Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
- sharedState->profiler.init(profiler, compilationUnit->totalParserStatusCount));
+ sharedState->profiler.init(profiler, compilationUnit->totalParserStatusCount()));
} else {
Q_UNUSED(profiler);
}
@@ -145,7 +146,7 @@ QQmlObjectCreator::~QQmlObjectCreator()
}
}
-QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlInstantiationInterrupt *interrupt)
+QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlInstantiationInterrupt *interrupt, int flags)
{
if (phase == CreatingObjectsPhase2) {
phase = ObjectsCreated;
@@ -159,14 +160,20 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
if (subComponentIndex == -1) {
objectToCreate = /*root object*/0;
} else {
- const QV4::CompiledData::Object *compObj = compilationUnit->objectAt(subComponentIndex);
- objectToCreate = compObj->bindingTable()->value.objectIndex;
+ Q_ASSERT(subComponentIndex >= 0);
+ if (flags & CreationFlags::InlineComponent) {
+ objectToCreate = subComponentIndex;
+ } else {
+ Q_ASSERT(flags & CreationFlags::NormalObject);
+ const QV4::CompiledData::Object *compObj = compilationUnit->objectAt(subComponentIndex);
+ objectToCreate = compObj->bindingTable()->value.objectIndex;
+ }
}
context = new QQmlContextData;
context->isInternal = true;
context->imports = compilationUnit->typeNameCache;
- context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex);
+ context->initFromTypeCompilationUnit(compilationUnit, flags & CreationFlags::NormalObject ? subComponentIndex : -1);
context->setParent(parentContext);
if (!sharedState->rootContext) {
@@ -179,7 +186,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
Q_ASSERT(sharedState->allJavaScriptObjects || topLevelCreator);
if (topLevelCreator)
- sharedState->allJavaScriptObjects = scope.alloc(compilationUnit->totalObjectCount);
+ sharedState->allJavaScriptObjects = scope.alloc(compilationUnit->totalObjectCount());
if (subComponentIndex == -1 && compilationUnit->dependentScripts.count()) {
QV4::ScopedObject scripts(scope, v4->newArrayObject(compilationUnit->dependentScripts.count()));
@@ -231,6 +238,9 @@ void QQmlObjectCreator::beginPopulateDeferred(QQmlContextData *newContext)
Q_ASSERT(topLevelCreator);
Q_ASSERT(!sharedState->allJavaScriptObjects);
+
+ QV4::Scope valueScope(v4);
+ sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount());
}
void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
@@ -248,7 +258,7 @@ void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
QV4::Scope valueScope(v4);
QScopedValueRollback<QV4::Value*> jsObjectGuard(sharedState->allJavaScriptObjects,
- valueScope.alloc(compilationUnit->totalObjectCount));
+ valueScope.alloc(compilationUnit->totalObjectCount()));
Q_ASSERT(topLevelCreator);
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
@@ -263,7 +273,6 @@ void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
qSwap(_compiledObject, obj);
-
qSwap(_ddata, declarativeData);
qSwap(_bindingTarget, bindingTarget);
qSwap(_vmeMetaObject, vmeMetaObject);
@@ -1172,7 +1181,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
Q_ASSERT(typeRef);
installPropertyCache = !typeRef->isFullyDynamicType;
QQmlType type = typeRef->type;
- if (type.isValid()) {
+ if (type.isValid() && !type.isInlineComponentType()) {
typeName = type.qmlTypeName();
void *ddataMemory = nullptr;
@@ -1206,17 +1215,31 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
} else {
Q_ASSERT(typeRef->compilationUnit);
typeName = typeRef->compilationUnit->fileName();
- if (typeRef->compilationUnit->unitData()->isSingleton())
+ // compilation unit is shared between root type and its inline component types
+ // so isSingleton errorneously returns true for inline components
+ if (typeRef->compilationUnit->unitData()->isSingleton() && !type.isInlineComponentType())
{
recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
return nullptr;
}
- QQmlObjectCreator subCreator(context, typeRef->compilationUnit, sharedState.data());
- instance = subCreator.create();
- if (!instance) {
- errors += subCreator.errors;
- return nullptr;
+
+ if (!type.isInlineComponentType()) {
+ QQmlObjectCreator subCreator(context, typeRef->compilationUnit, sharedState.data());
+ instance = subCreator.create();
+ if (!instance) {
+ errors += subCreator.errors;
+ return nullptr;
+ }
+ } else {
+ int subObjectId = type.inlineComponendId();
+ QScopedValueRollback<int> rollback {typeRef->compilationUnit->icRoot, subObjectId};
+ QQmlObjectCreator subCreator(context, typeRef->compilationUnit, sharedState.data());
+ instance = subCreator.create(subObjectId, nullptr, nullptr, CreationFlags::InlineComponent);
+ if (!instance) {
+ errors += subCreator.errors;
+ return nullptr;
+ }
}
}
if (instance->isWidgetType()) {
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 8b6cb67341..f8ad90be15 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -111,7 +111,8 @@ public:
QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, QQmlContextData *creationContext, QQmlIncubatorPrivate *incubator = nullptr);
~QQmlObjectCreator();
- QObject *create(int subComponentIndex = -1, QObject *parent = nullptr, QQmlInstantiationInterrupt *interrupt = nullptr);
+ enum CreationFlags { NormalObject = 1, InlineComponent = 2 };
+ QObject *create(int subComponentIndex = -1, QObject *parent = nullptr, QQmlInstantiationInterrupt *interrupt = nullptr, int flags = NormalObject);
bool populateDeferredProperties(QObject *instance, const QQmlData::DeferredData *deferredData);
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 71a8a255a9..c4afbbd598 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -71,10 +71,10 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
{
QQmlPropertyData::Flags flags;
- flags.isConstant = p.isConstant();
- flags.isWritable = p.isWritable();
- flags.isResettable = p.isResettable();
- flags.isFinal = p.isFinal();
+ flags.setIsConstant(p.isConstant());
+ flags.setIsWritable(p.isWritable());
+ flags.setIsResettable(p.isResettable());
+ flags.setIsFinal(p.isFinal());
if (p.isEnumType())
flags.type = QQmlPropertyData::Flags::EnumType;
@@ -166,21 +166,21 @@ void QQmlPropertyData::load(const QMetaMethod &m)
m_flags.type = Flags::FunctionType;
if (m.methodType() == QMetaMethod::Signal) {
- m_flags.isSignal = true;
+ m_flags.setIsSignal(true);
} else if (m.methodType() == QMetaMethod::Constructor) {
- m_flags.isConstructor = true;
+ m_flags.setIsConstructor(true);
setPropType(QMetaType::QObjectStar);
}
const int paramCount = m.parameterCount();
if (paramCount) {
- m_flags.hasArguments = true;
+ m_flags.setHasArguments(true);
if ((paramCount == 1) && (m.parameterTypes().constFirst() == "QQmlV4Function*"))
- m_flags.isV4Function = true;
+ m_flags.setIsV4Function(true);
}
if (m.attributes() & QMetaMethod::Cloned)
- m_flags.isCloned = true;
+ m_flags.setIsCloned(true);
Q_ASSERT(m.revision() <= Q_INT16_MAX);
setRevision(m.revision());
@@ -320,7 +320,7 @@ void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flag
data.setArguments(nullptr);
QQmlPropertyData handler = data;
- handler.m_flags.isSignalHandler = true;
+ handler.m_flags.setIsSignalHandler(true);
if (types) {
int argumentCount = *types;
@@ -519,7 +519,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
data->setFlags(methodFlags);
data->lazyLoad(m);
- data->m_flags.isDirect = !dynamicMetaObject;
+ data->m_flags.setIsDirect(!dynamicMetaObject);
Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
data->setMetaObjectOffset(allowedRevisionCache.count() - 1);
@@ -527,7 +527,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
if (data->isSignal()) {
sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
*sigdata = *data;
- sigdata->m_flags.isSignalHandler = true;
+ sigdata->m_flags.setIsSignalHandler(true);
}
QQmlPropertyData *old = nullptr;
@@ -569,7 +569,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
if (old) {
// We only overload methods in the same class, exactly like C++
if (old->isFunction() && old->coreIndex() >= methodOffset)
- data->m_flags.isOverload = true;
+ data->m_flags.setIsOverload(true);
data->markAsOverrideOf(old);
}
@@ -600,7 +600,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
data->lazyLoad(p);
data->setTypeMinorVersion(typeMinorVersion);
- data->m_flags.isDirect = !dynamicMetaObject;
+ data->m_flags.setIsDirect(!dynamicMetaObject);
Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
data->setMetaObjectOffset(allowedRevisionCache.count() - 1);
@@ -626,7 +626,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
}
if (isGadget) // always dispatch over a 'normal' meta-call so the QQmlValueType can intercept
- data->m_flags.isDirect = false;
+ data->m_flags.setIsDirect(false);
else
data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset);
if (old)
@@ -849,7 +849,7 @@ void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
setOverrideIndexIsProperty(!predecessor->isFunction());
setOverrideIndex(predecessor->coreIndex());
- predecessor->m_flags.isOverridden = true;
+ predecessor->m_flags.setIsOverridden(true);
}
QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int argc, const QList<QByteArray> &names)
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index 1f636c8347..a050a0bf0a 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -55,6 +55,10 @@
#include <private/qqmlmetaobject_p.h>
#include <private/qqmlpropertyresolver_p.h>
#include <private/qqmltypedata_p.h>
+#include <private/inlinecomponentutils_p.h>
+
+#include <QScopedValueRollback>
+#include <vector>
QT_BEGIN_NAMESPACE
@@ -115,8 +119,12 @@ public:
QQmlJS::DiagnosticMessage buildMetaObjects();
+ enum class VMEMetaObjectIsRequired {
+ Maybe,
+ Always
+ };
protected:
- QQmlJS::DiagnosticMessage buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context);
+ QQmlJS::DiagnosticMessage buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired);
QQmlRefPointer<QQmlPropertyCache> propertyCacheForObject(const CompiledObject *obj, const QQmlBindingInstantiationContext &context, QQmlJS::DiagnosticMessage *error) const;
QQmlJS::DiagnosticMessage createMetaObject(int objectIndex, const CompiledObject *obj, const QQmlRefPointer<QQmlPropertyCache> &baseTypeCache);
@@ -129,7 +137,8 @@ protected:
const QQmlImports * const imports;
QQmlPropertyCacheVector *propertyCaches;
QQmlPendingGroupPropertyBindings *pendingGroupPropertyBindings;
- const QByteArray typeClassName;
+ QByteArray typeClassName; // not const as we temporarily chang it for inline components
+ unsigned int currentRoot; // set to objectID of inline component root when handling inline components
};
template <typename ObjectContainer>
@@ -151,12 +160,59 @@ inline QQmlPropertyCacheCreator<ObjectContainer>::QQmlPropertyCacheCreator(QQmlP
template <typename ObjectContainer>
inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjects()
{
+ using namespace icutils;
QQmlBindingInstantiationContext context;
- return buildMetaObjectRecursively(/*root object*/0, context);
+
+ // get a list of all inline components
+ using InlineComponent = typename std::remove_reference<decltype (*(std::declval<CompiledObject>().inlineComponentsBegin()))>::type;
+ std::vector<InlineComponent> allICs {};
+ for (int i=0; i != objectContainer->objectCount(); ++i) {
+ const CompiledObject *obj = objectContainer->objectAt(i);
+ for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
+ allICs.push_back(*it);
+ }
+ }
+
+ // create a graph on inline components referencing inline components
+ std::vector<Node> nodes;
+ nodes.resize(allICs.size());
+ std::iota(nodes.begin(), nodes.end(), 0);
+ AdjacencyList adjacencyList;
+ adjacencyList.resize(nodes.size());
+ fillAdjacencyListForInlineComponents(objectContainer, adjacencyList, nodes, allICs);
+
+ bool hasCycle = false;
+ auto nodesSorted = topoSort(nodes, adjacencyList, hasCycle);
+
+ if (hasCycle) {
+ QQmlJS::DiagnosticMessage diag;
+ diag.message = QLatin1String("Inline components form a cycle!");
+ return diag;
+ }
+
+ // create meta objects for inline components before compiling actual root component
+ for (auto nodeIt = nodesSorted.rbegin(); nodeIt != nodesSorted.rend(); ++nodeIt) {
+ const auto &ic = allICs[nodeIt->index];
+ QV4::ResolvedTypeReference *typeRef = objectContainer->resolvedType(ic.nameIndex);
+ Q_ASSERT(propertyCaches->at(ic.objectIndex) == nullptr);
+ Q_ASSERT(typeRef->typePropertyCache.isNull()); // not set yet
+
+ QByteArray icTypeName { objectContainer->stringAt(ic.nameIndex).toUtf8() };
+ QScopedValueRollback<QByteArray> nameChange {typeClassName, icTypeName};
+ QScopedValueRollback<unsigned int> rootChange {currentRoot, ic.objectIndex};
+ QQmlJS::DiagnosticMessage diag = buildMetaObjectRecursively(ic.objectIndex, context, VMEMetaObjectIsRequired::Always);
+ if (diag.isValid()) {
+ return diag;
+ }
+ typeRef->typePropertyCache = propertyCaches->at(ic.objectIndex);
+ Q_ASSERT(!typeRef->typePropertyCache.isNull());
+ }
+
+ return buildMetaObjectRecursively(/*root object*/0, context, VMEMetaObjectIsRequired::Maybe);
}
template <typename ObjectContainer>
-inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context)
+inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecursively(int objectIndex, const QQmlBindingInstantiationContext &context, VMEMetaObjectIsRequired isVMERequired)
{
auto isAddressable = [](const QUrl &url) {
const QString fileName = url.fileName();
@@ -164,7 +220,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil
};
const CompiledObject *obj = objectContainer->objectAt(objectIndex);
- bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0
+ bool needVMEMetaObject = isVMERequired == VMEMetaObjectIsRequired::Always || obj->propertyCount() != 0 || obj->aliasCount() != 0
|| obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0
|| (((obj->flags & QV4::CompiledData::Object::IsComponent)
|| (objectIndex == 0 && isAddressable(objectContainer->url())))
@@ -230,7 +286,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::buil
if (!context.resolveInstantiatingProperty())
pendingGroupPropertyBindings->append(context);
- QQmlJS::DiagnosticMessage error = buildMetaObjectRecursively(binding->value.objectIndex, context);
+ QQmlJS::DiagnosticMessage error = buildMetaObjectRecursively(binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe);
if (error.isValid())
return error;
}
@@ -247,6 +303,7 @@ inline QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCacheCreator<ObjectContaine
return context.instantiatingPropertyCache(enginePrivate);
} else if (obj->inheritedTypeNameIndex != 0) {
auto *typeRef = objectContainer->resolvedType(obj->inheritedTypeNameIndex);
+ QQmlType qmltype = typeRef->type;
Q_ASSERT(typeRef);
if (typeRef->isFullyDynamicType) {
@@ -298,7 +355,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
QByteArray newClassName;
- if (objectIndex == /*root object*/0) {
+ if (objectIndex == /*root object*/0 || int(currentRoot) == objectIndex) {
newClassName = typeClassName;
}
if (newClassName.isEmpty()) {
@@ -428,7 +485,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
auto flags = QQmlPropertyData::defaultSignalFlags();
if (paramCount)
- flags.hasArguments = true;
+ flags.setHasArguments(true);
QString signalName = stringAt(s->nameIndex);
if (seenSignals.contains(signalName))
@@ -457,7 +514,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
auto formal = function->formalsBegin();
auto end = function->formalsEnd();
for ( ; formal != end; ++formal) {
- flags.hasArguments = true;
+ flags.setHasArguments(true);
parameterNames << stringAt(formal->nameIndex).toUtf8();
int type = metaTypeForParameter(formal->type);
if (type == QMetaType::UnknownType)
@@ -504,18 +561,31 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
}
- Q_ASSERT(qmltype.isValid());
- if (qmltype.isComposite()) {
- QQmlMetaType::CompositeMetaTypeIds typeIds;
- if (selfReference) {
- typeIds = objectContainer->typeIds();
+ // inline components are not necessarily valid yet
+ Q_ASSERT(qmltype.isValid() || qmltype.isInlineComponentType());
+ if (qmltype.isComposite() || qmltype.isInlineComponentType()) {
+ CompositeMetaTypeIds typeIds;
+ if (qmltype.isInlineComponentType()) {
+ auto objectId = qmltype.inlineComponendId();
+ auto containingType = qmltype.containingType();
+ if (containingType.isValid()) {
+ auto icType = containingType.lookupInlineComponentById(objectId);
+ typeIds = {icType.typeId(), icType.qListTypeId()};
+ } else {
+ typeIds = {};
+ }
+ if (!typeIds.isValid()) // type has not been registered yet, we must be in containing type
+ typeIds = objectContainer->typeIdsForComponent(objectId);
+ Q_ASSERT(typeIds.isValid());
+ } else if (selfReference) {
+ typeIds = objectContainer->typeIdsForComponent();
} else {
QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
Q_ASSERT(tdata);
Q_ASSERT(tdata->isComplete());
auto compilationUnit = tdata->compilationUnit();
- typeIds = compilationUnit->typeIds();
+ typeIds = compilationUnit->typeIdsForComponent();
}
if (p->isList) {
@@ -539,7 +609,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheCreator<ObjectContainer>::crea
}
if (!p->isReadOnly && !p->isList)
- propertyFlags.isWritable = true;
+ propertyFlags.setIsWritable(true);
QString propertyName = stringAt(p->nameIndex);
@@ -578,7 +648,7 @@ inline int QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const
return qmltype.typeId();
if (selfReference)
- return objectContainer->typeIds().id;
+ return objectContainer->typeIdsForComponent().id;
QQmlRefPointer<QQmlTypeData> tdata = enginePrivate->typeLoader.getType(qmltype.sourceUrl());
Q_ASSERT(tdata);
@@ -721,7 +791,7 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>:
bool writable = false;
bool resettable = false;
- propertyFlags->isAlias = true;
+ propertyFlags->setIsAlias(true);
if (alias.aliasToLocalAlias) {
const QV4::CompiledData::Alias *lastAlias = &alias;
@@ -823,8 +893,8 @@ inline QQmlJS::DiagnosticMessage QQmlPropertyCacheAliasCreator<ObjectContainer>:
}
}
- propertyFlags->isWritable = !(alias.flags & QV4::CompiledData::Alias::IsReadOnly) && writable;
- propertyFlags->isResettable = resettable;
+ propertyFlags->setIsWritable(!(alias.flags & QV4::CompiledData::Alias::IsReadOnly) && writable);
+ propertyFlags->setIsResettable(resettable);
return QQmlJS::DiagnosticMessage();
}
diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h
index dec696226e..2d9091edcd 100644
--- a/src/qml/qml/qqmlpropertydata_p.h
+++ b/src/qml/qml/qqmlpropertydata_p.h
@@ -52,6 +52,7 @@
//
#include <private/qobject_p.h>
+#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
@@ -69,6 +70,7 @@ public:
typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction;
struct Flags {
+ friend class QQmlPropertyData;
enum Types {
OtherType = 0,
FunctionType = 1, // Is an invokable
@@ -87,30 +89,34 @@ public:
// trySetStaticMetaCallFunction for details.
// (Note: this padding is done here, because certain compilers have surprising behavior
// when an enum is declared in-between two bit fields.)
- enum { BitsLeftInFlags = 10 };
+ enum { BitsLeftInFlags = 15 };
unsigned otherBits : BitsLeftInFlags; // align to 32 bits
- // Can apply to all properties, except IsFunction
- unsigned isConstant : 1; // Has CONST flag
- unsigned isWritable : 1; // Has WRITE function
- unsigned isResettable : 1; // Has RESET function
- unsigned isAlias : 1; // Is a QML alias to another property
- unsigned isFinal : 1; // Has FINAL flag
- unsigned isOverridden : 1; // Is overridden by a extension property
- unsigned isDirect : 1; // Exists on a C++ QMetaObject
-
+ // Members of the form aORb can only be a when type is not FunctionType, and only be
+ // b when type equals FunctionType. For that reason, the semantic meaning of the bit is
+ // overloaded, and the accessor functions are used to get the correct value
+ //
+ // Moreover, isSignalHandler, isOverload and isCloned and isConstructor make only sense
+ // for functions, too (and could at a later point be reused for flags that only make sense
+ // for non-functions)
+ //
+ // Lastly, isDirect and isOverridden apply to both functions and non-functions
+ private:
+ unsigned isConstantORisVMEFunction : 1; // Has CONST flag OR Function was added by QML
+ unsigned isWritableORhasArguments : 1; // Has WRITE function OR Function takes arguments
+ unsigned isResettableORisSignal : 1; // Has RESET function OR Function is a signal
+ unsigned isAliasORisVMESignal : 1; // Is a QML alias to another property OR Signal was added by QML
+ unsigned isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4Function* args
+ unsigned isSignalHandler : 1; // Function is a signal handler
+ unsigned isOverload : 1; // Function is an overload of another function
+ unsigned isCloned : 1; // The function was marked as cloned
+ unsigned isConstructor : 1; // The function was marked is a constructor
+ unsigned isDirect : 1; // Exists on a C++ QMetaObject
+ unsigned isOverridden : 1; // Is overridden by a extension property
+ public:
unsigned type : 4; // stores an entry of Types
// Apply only to IsFunctions
- unsigned isVMEFunction : 1; // Function was added by QML
- unsigned hasArguments : 1; // Function takes arguments
- unsigned isSignal : 1; // Function is a signal
- unsigned isVMESignal : 1; // Signal was added by QML
- unsigned isV4Function : 1; // Function takes QQmlV4Function* args
- unsigned isSignalHandler : 1; // Function is a signal handler
- unsigned isOverload : 1; // Function is an overload of another function
- unsigned isCloned : 1; // The function was marked as cloned
- unsigned isConstructor : 1; // The function was marked is a constructor
// Internal QQmlPropertyCache flags
unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved
@@ -119,8 +125,85 @@ public:
inline Flags();
inline bool operator==(const Flags &other) const;
inline void copyPropertyTypeFlags(Flags from);
+
+ void setIsConstant(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isConstantORisVMEFunction = b;
+ }
+
+ void setIsWritable(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isWritableORhasArguments = b;
+ }
+
+ void setIsResettable(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isResettableORisSignal = b;
+ }
+
+ void setIsAlias(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isAliasORisVMESignal = b;
+ }
+
+ void setIsFinal(bool b) {
+ Q_ASSERT(type != FunctionType);
+ isFinalORisV4Function = b;
+ }
+
+ void setIsOverridden(bool b) {
+ isOverridden = b;
+ }
+
+ void setIsDirect(bool b) {
+ isDirect = b;
+ }
+
+ void setIsVMEFunction(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isConstantORisVMEFunction = b;
+ }
+ void setHasArguments(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isWritableORhasArguments = b;
+ }
+ void setIsSignal(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isResettableORisSignal = b;
+ }
+ void setIsVMESignal(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isAliasORisVMESignal = b;
+ }
+
+ void setIsV4Function(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isFinalORisV4Function = b;
+ }
+
+ void setIsSignalHandler(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isSignalHandler = b;
+ }
+
+ void setIsOverload(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isOverload = b;
+ }
+
+ void setIsCloned(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isCloned = b;
+ }
+
+ void setIsConstructor(bool b) {
+ Q_ASSERT(type == FunctionType);
+ isConstructor = b;
+ }
+
};
+
inline bool operator==(const QQmlPropertyData &) const;
Flags flags() const { return m_flags; }
@@ -133,14 +216,14 @@ public:
bool isValid() const { return coreIndex() != -1; }
- bool isConstant() const { return m_flags.isConstant; }
- bool isWritable() const { return m_flags.isWritable; }
- void setWritable(bool onoff) { m_flags.isWritable = onoff; }
- bool isResettable() const { return m_flags.isResettable; }
- bool isAlias() const { return m_flags.isAlias; }
- bool isFinal() const { return m_flags.isFinal; }
+ bool isConstant() const { return !isFunction() && m_flags.isConstantORisVMEFunction; }
+ bool isWritable() const { return !isFunction() && m_flags.isWritableORhasArguments; }
+ void setWritable(bool onoff) { Q_ASSERT(!isFunction()); m_flags.isWritableORhasArguments = onoff; }
+ bool isResettable() const { return !isFunction() && m_flags.isResettableORisSignal; }
+ bool isAlias() const { return !isFunction() && m_flags.isAliasORisVMESignal; }
+ bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; }
bool isOverridden() const { return m_flags.isOverridden; }
- bool isDirect() const { return m_flags.isDirect; }
+ bool isDirect() const { return m_flags.isOverload; }
bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
bool isFunction() const { return m_flags.type == Flags::FunctionType; }
bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
@@ -150,15 +233,15 @@ public:
bool isQJSValue() const { return m_flags.type == Flags::QJSValueType; }
bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
- bool isVMEFunction() const { return m_flags.isVMEFunction; }
- bool hasArguments() const { return m_flags.hasArguments; }
- bool isSignal() const { return m_flags.isSignal; }
- bool isVMESignal() const { return m_flags.isVMESignal; }
- bool isV4Function() const { return m_flags.isV4Function; }
+ bool isVMEFunction() const { return isFunction() && m_flags.isConstantORisVMEFunction; }
+ bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; }
+ bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; }
+ bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; }
+ bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; }
bool isSignalHandler() const { return m_flags.isSignalHandler; }
bool isOverload() const { return m_flags.isOverload; }
void setOverload(bool onoff) { m_flags.isOverload = onoff; }
- bool isCloned() const { return m_flags.isCloned; }
+ bool isCloned() const { return isFunction() && m_flags.isCloned; }
bool isConstructor() const { return m_flags.isConstructor; }
bool hasOverride() const { return overrideIndex() >= 0; }
@@ -294,9 +377,9 @@ public:
static Flags defaultSignalFlags()
{
Flags f;
- f.isSignal = true;
f.type = Flags::FunctionType;
- f.isVMESignal = true;
+ f.setIsSignal(true);
+ f.setIsVMESignal(true);
return f;
}
@@ -304,7 +387,7 @@ public:
{
Flags f;
f.type = Flags::FunctionType;
- f.isVMEFunction = true;
+ f.setIsVMEFunction(true);
return f;
}
@@ -348,44 +431,32 @@ bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
QQmlPropertyData::Flags::Flags()
: otherBits(0)
- , isConstant(false)
- , isWritable(false)
- , isResettable(false)
- , isAlias(false)
- , isFinal(false)
- , isOverridden(false)
- , isDirect(false)
- , type(OtherType)
- , isVMEFunction(false)
- , hasArguments(false)
- , isSignal(false)
- , isVMESignal(false)
- , isV4Function(false)
+ , isConstantORisVMEFunction(false)
+ , isWritableORhasArguments(false)
+ , isResettableORisSignal(false)
+ , isAliasORisVMESignal(false)
+ , isFinalORisV4Function(false)
, isSignalHandler(false)
, isOverload(false)
, isCloned(false)
, isConstructor(false)
+ , isOverridden(false)
+ , type(OtherType)
, notFullyResolved(false)
, overrideIndexIsProperty(false)
{}
bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) const
{
- return isConstant == other.isConstant &&
- isWritable == other.isWritable &&
- isResettable == other.isResettable &&
- isAlias == other.isAlias &&
- isFinal == other.isFinal &&
+ return isConstantORisVMEFunction == other.isConstantORisVMEFunction &&
+ isWritableORhasArguments == other.isWritableORhasArguments &&
+ isResettableORisSignal == other.isResettableORisSignal &&
+ isAliasORisVMESignal == other.isAliasORisVMESignal &&
+ isFinalORisV4Function == other.isFinalORisV4Function &&
isOverridden == other.isOverridden &&
- type == other.type &&
- isVMEFunction == other.isVMEFunction &&
- hasArguments == other.hasArguments &&
- isSignal == other.isSignal &&
- isVMESignal == other.isVMESignal &&
- isV4Function == other.isV4Function &&
isSignalHandler == other.isSignalHandler &&
- isOverload == other.isOverload &&
isCloned == other.isCloned &&
+ type == other.type &&
isConstructor == other.isConstructor &&
notFullyResolved == other.notFullyResolved &&
overrideIndexIsProperty == other.overrideIndexIsProperty;
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index 8f6e2737cc..8762dc328d 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -100,6 +100,9 @@ QVector<QQmlJS::DiagnosticMessage> QQmlPropertyValidator::validateObject(
int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
{
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(objectIndex);
+ for (auto it = obj->inlineComponentsBegin(); it != obj->inlineComponentsEnd(); ++it) {
+ validateObject(it->objectIndex, /* instantiatingBinding*/ nullptr);
+ }
if (obj->flags & QV4::CompiledData::Object::IsComponent) {
Q_ASSERT(obj->nBindings == 1);
diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp
index 4a211ffa53..28fefca239 100644
--- a/src/qml/qml/qqmltype.cpp
+++ b/src/qml/qml/qqmltype.cpp
@@ -84,6 +84,9 @@ QQmlTypePrivate::QQmlTypePrivate(QQmlType::RegistrationType type)
case QQmlType::CompositeType:
extraData.fd = new QQmlCompositeTypeData;
break;
+ case QQmlType::InlineComponentType:
+ extraData.id = new QQmlInlineTypeData;
+ break;
default: qFatal("QQmlTypePrivate Internal Error.");
}
}
@@ -106,6 +109,9 @@ QQmlTypePrivate::~QQmlTypePrivate()
case QQmlType::CompositeType:
delete extraData.fd;
break;
+ case QQmlType::InlineComponentType:
+ delete extraData.id;
+ break;
default: //Also InterfaceType, because it has no extra data
break;
}
@@ -426,6 +432,12 @@ void QQmlTypePrivate::insertEnumsFromPropertyCache(const QQmlPropertyCache *cach
insertEnums(cppMetaObject);
}
+void QQmlTypePrivate::setContainingType(QQmlType *containingType)
+{
+ Q_ASSERT(regType == QQmlType::InlineComponentType);
+ extraData.id->containingType = containingType->d.data();
+}
+
void QQmlTypePrivate::setName(const QString &uri, const QString &element)
{
module = uri;
@@ -440,6 +452,8 @@ QByteArray QQmlType::typeName() const
return d->extraData.sd->singletonInstanceInfo->typeName.toUtf8();
else if (d->baseMetaObject)
return d->baseMetaObject->className();
+ else if (d->regType == InlineComponentType)
+ return d->extraData.id->inlineComponentName.toUtf8();
}
return QByteArray();
}
@@ -561,7 +575,11 @@ bool QQmlType::isComposite() const
bool QQmlType::isCompositeSingleton() const
{
- return d && d->regType == CompositeSingletonType;
+ // if the outer type is a composite singleton, d->regType will indicate that even for
+ // the inline component type
+ // however, inline components can -at least for now- never be singletons
+ // so we just do one additional check
+ return d && d->regType == CompositeSingletonType && !isInlineComponentType();
}
bool QQmlType::isQObjectSingleton() const
@@ -677,9 +695,28 @@ int QQmlType::index() const
return d ? d->index : -1;
}
+bool QQmlType::isInlineComponentType() const {
+ return d ? d->regType == QQmlType::InlineComponentType : false;
+}
+
+int QQmlType::inlineComponendId() const {
+ bool ok = false;
+ if (d->regType == QQmlType::RegistrationType::InlineComponentType) {
+ Q_ASSERT(d->extraData.id->objectId != -1);
+ return d->extraData.id->objectId;
+ }
+ int subObjectId = sourceUrl().fragment().toInt(&ok);
+ return ok ? subObjectId : -1;
+}
+
QUrl QQmlType::sourceUrl() const
{
- return d ? d->sourceUrl() : QUrl();
+ auto url = d ? d->sourceUrl() : QUrl();
+ if (url.isValid() && d->regType == QQmlType::RegistrationType::InlineComponentType && d->extraData.id->objectId) {
+ Q_ASSERT(url.hasFragment());
+ url.setFragment(QString::number(inlineComponendId()));
+ }
+ return url;
}
int QQmlType::enumValue(QQmlEnginePrivate *engine, const QHashedStringRef &name, bool *ok) const
@@ -845,6 +882,19 @@ int QQmlType::scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &scope
return -1;
}
+int QQmlType::inlineComponentObjectId()
+{
+ if (!isInlineComponentType())
+ return -1;
+ return d->extraData.id->objectId;
+}
+
+void QQmlType::setInlineComponentObjectId(int id) const
+{
+ Q_ASSERT(d && d->regType == QQmlType::InlineComponentType);
+ d->extraData.id->objectId = id;
+}
+
void QQmlType::refHandle(const QQmlTypePrivate *priv)
{
if (priv)
@@ -864,4 +914,63 @@ int QQmlType::refCount(const QQmlTypePrivate *priv)
return -1;
}
+int QQmlType::lookupInlineComponentIdByName(const QString &name) const
+{
+ Q_ASSERT(d);
+ return d->namesToInlineComponentObjectIndex.value(name, -1);
+}
+
+QQmlType QQmlType::containingType() const
+{
+ Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType);
+ auto ret = QQmlType {d->extraData.id->containingType};
+ Q_ASSERT(!ret.isInlineComponentType());
+ return ret;
+}
+
+QQmlType QQmlType::lookupInlineComponentById(int objectid) const
+{
+ Q_ASSERT(d);
+ return d->objectIdToICType.value(objectid, QQmlType(nullptr));
+}
+
+int QQmlType::generatePlaceHolderICId() const
+{
+ Q_ASSERT(d);
+ int id = -2;
+ for (auto it = d->objectIdToICType.keyBegin(); it != d->objectIdToICType.keyEnd(); ++it)
+ if (*it < id)
+ id = *it;
+ return id;
+}
+
+void QQmlType::associateInlineComponent(const QString &name, int objectID, const CompositeMetaTypeIds &metaTypeIds, QQmlType existingType)
+{
+ auto priv = existingType.isValid() ? const_cast<QQmlTypePrivate *>(existingType.d.data()) : new QQmlTypePrivate { RegistrationType::InlineComponentType } ;
+ priv->setName( QString::fromUtf8(typeName()), name);
+ auto icUrl = QUrl(sourceUrl());
+ icUrl.setFragment(QString::number(objectID));
+ priv->extraData.id->url = icUrl;
+ priv->extraData.id->containingType = d.data();
+ priv->extraData.id->objectId = objectID;
+ priv->typeId = metaTypeIds.id;
+ priv->listId = metaTypeIds.listId;
+ d->namesToInlineComponentObjectIndex.insert(name, objectID);
+ QQmlType icType(priv);
+ d->objectIdToICType.insert(objectID, icType);
+}
+
+void QQmlType::setPendingResolutionName(const QString &name)
+{
+ Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType);
+ Q_ASSERT(d->extraData.id->inlineComponentName == name|| d->extraData.id->inlineComponentName.isEmpty());
+ d->extraData.id->inlineComponentName = name;
+}
+
+QString QQmlType::pendingResolutionName() const
+{
+ Q_ASSERT(d && d->regType == QQmlType::RegistrationType::InlineComponentType);
+ return d->extraData.id->inlineComponentName;
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltype_p.h b/src/qml/qml/qqmltype_p.h
index af134b21f1..387baa74bb 100644
--- a/src/qml/qml/qqmltype_p.h
+++ b/src/qml/qml/qqmltype_p.h
@@ -74,6 +74,7 @@ class QQmlPropertyCache;
namespace QV4 {
struct String;
}
+struct CompositeMetaTypeIds;
class Q_QML_PRIVATE_EXPORT QQmlType
{
@@ -144,6 +145,9 @@ public:
int index() const;
+ bool isInlineComponentType() const;
+ int inlineComponendId() const;
+
struct Q_QML_PRIVATE_EXPORT SingletonInstanceInfo
{
QJSValue (*scriptCallback)(QQmlEngine *, QJSEngine *) = nullptr;
@@ -166,6 +170,8 @@ public:
int scopedEnumValue(QQmlEnginePrivate *engine, int index, const QString &, bool *ok) const;
int scopedEnumValue(QQmlEnginePrivate *engine, const QByteArray &, const QByteArray &, bool *ok) const;
int scopedEnumValue(QQmlEnginePrivate *engine, const QStringRef &, const QStringRef &, bool *ok) const;
+ int inlineComponentObjectId();
+ void setInlineComponentObjectId(int id) const; // TODO: const setters are BAD
const QQmlTypePrivate *priv() const { return d.data(); }
static void refHandle(const QQmlTypePrivate *priv);
@@ -178,9 +184,19 @@ public:
InterfaceType = 2,
CompositeType = 3,
CompositeSingletonType = 4,
+ InlineComponentType = 5,
AnyRegistrationType = 255
};
+ QQmlType containingType() const;
+ int lookupInlineComponentIdByName(const QString &name) const;
+ QQmlType lookupInlineComponentById(int objectid) const;
+ int generatePlaceHolderICId() const;
+
+ void associateInlineComponent(const QString &name, int objectID, const CompositeMetaTypeIds &metaTypeIds, QQmlType existingType);
+ void setPendingResolutionName(const QString &name);
+ QString pendingResolutionName() const;
+
private:
friend class QQmlTypePrivate;
friend uint qHash(const QQmlType &t, uint seed);
diff --git a/src/qml/qml/qqmltype_p_p.h b/src/qml/qml/qqmltype_p_p.h
index 51f776178c..43344827db 100644
--- a/src/qml/qml/qqmltype_p_p.h
+++ b/src/qml/qml/qqmltype_p_p.h
@@ -56,6 +56,7 @@
#include <private/qqmlproxymetaobject_p.h>
#include <private/qqmlrefcount_p.h>
#include <private/qqmlpropertycache_p.h>
+#include <private/qqmlmetatype_p.h>
QT_BEGIN_NAMESPACE
@@ -69,6 +70,7 @@ public:
void initEnums(QQmlEnginePrivate *engine) const;
void insertEnums(const QMetaObject *metaObject) const;
void insertEnumsFromPropertyCache(const QQmlPropertyCache *cache) const;
+ void setContainingType(QQmlType *containingType);
QUrl sourceUrl() const
{
@@ -77,6 +79,8 @@ public:
return extraData.fd->url;
case QQmlType::CompositeSingletonType:
return extraData.sd->singletonInstanceInfo->url;
+ case QQmlType::InlineComponentType:
+ return extraData.id->url;
default:
return QUrl();
}
@@ -130,10 +134,23 @@ public:
QUrl url;
};
+ struct QQmlInlineTypeData
+ {
+ QUrl url = QUrl();
+ // The containing type stores a pointer to the inline component type
+ // Using QQmlType here would create a reference cycle
+ // As the inline component type cannot outlive the containing type
+ // this should still be fine
+ QQmlTypePrivate const * containingType = nullptr;
+ QString inlineComponentName = QString();
+ int objectId = -1;
+ };
+
union extraData {
QQmlCppTypeData* cd;
QQmlSingletonTypeData* sd;
QQmlCompositeTypeData* fd;
+ QQmlInlineTypeData* id;
} extraData;
const char *iid;
@@ -160,6 +177,8 @@ public:
mutable QList<QStringHash<int>*> scopedEnums;
void setName(const QString &uri, const QString &element);
+ mutable QHash<QString, int> namesToInlineComponentObjectIndex;
+ mutable QHash<int, QQmlType> objectIdToICType;
private:
~QQmlTypePrivate() override;
diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp
index b4d56c9e49..842ca697e0 100644
--- a/src/qml/qml/qqmltypecompiler.cpp
+++ b/src/qml/qml/qqmltypecompiler.cpp
@@ -58,10 +58,10 @@ QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *type
QV4::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
: resolvedTypes(resolvedTypeCache)
, engine(engine)
- , typeData(typeData)
, dependencyHasher(dependencyHasher)
- , typeNameCache(typeNameCache)
, document(parsedQML)
+ , typeNameCache(typeNameCache)
+ , typeData(typeData)
{
}
@@ -279,9 +279,9 @@ void QQmlTypeCompiler::addImport(const QString &module, const QString &qualifier
document->imports.append(import);
}
-QQmlMetaType::CompositeMetaTypeIds QQmlTypeCompiler::typeIds() const
+CompositeMetaTypeIds QQmlTypeCompiler::typeIdsForComponent(int objectId) const
{
- return typeData->typeIds();
+ return typeData->typeIds(objectId);
}
QQmlCompilePass::QQmlCompilePass(QQmlTypeCompiler *typeCompiler)
@@ -1215,7 +1215,7 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
if (obj->idNameIndex != 0)
_seenObjectWithId = true;
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ if (obj->flags & QV4::CompiledData::Object::IsComponent && !obj->isInlineComponent) {
Q_ASSERT(obj->bindingCount() == 1);
const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
diff --git a/src/qml/qml/qqmltypecompiler_p.h b/src/qml/qml/qqmltypecompiler_p.h
index b43089dc06..319df8673b 100644
--- a/src/qml/qml/qqmltypecompiler_p.h
+++ b/src/qml/qml/qqmltypecompiler_p.h
@@ -79,7 +79,9 @@ struct QQmlTypeCompiler
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler)
public:
- QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document,
+ QQmlTypeCompiler(QQmlEnginePrivate *engine,
+ QQmlTypeData *typeData,
+ QmlIR::Document *document,
const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
QV4::ResolvedTypeReferenceMap *resolvedTypeCache,
const QV4::CompiledData::DependentTypesHasher &dependencyHasher);
@@ -129,14 +131,12 @@ public:
return resolvedTypes->value(id);
}
- QQmlMetaType::CompositeMetaTypeIds typeIds() const;
+ CompositeMetaTypeIds typeIdsForComponent(int objectId = 0) const;
private:
QList<QQmlError> errors;
QQmlEnginePrivate *engine;
- QQmlTypeData *typeData;
const QV4::CompiledData::DependentTypesHasher &dependencyHasher;
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QmlIR::Document *document;
// index is string index of type name (use obj->inheritedTypeNameIndex)
QHash<int, QQmlCustomParser*> customParsers;
@@ -144,6 +144,9 @@ private:
// index in first hash is component index, vector inside contains object indices of objects with id property
QVector<quint32> m_componentRoots;
QQmlPropertyCacheVector m_propertyCaches;
+
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
+ QQmlTypeData *typeData;
};
struct QQmlCompilePass
diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp
index 22587c226a..f7abe67921 100644
--- a/src/qml/qml/qqmltypedata.cpp
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -92,6 +92,25 @@ QV4::ExecutableCompilationUnit *QQmlTypeData::compilationUnit() const
return m_compiledData.data();
}
+QV4::ExecutableCompilationUnit *QQmlTypeData::compilationUnitForInlineComponent(unsigned int icObjectId) const
+{
+ Q_ASSERT(m_document || m_compiledData);
+ if (m_compiledData)
+ return m_compiledData.data();
+ for (auto it = m_document->objects.begin(); it != m_document->objects.end(); ++it) {
+ auto object = *it;
+ auto icIt = std::find_if(object->inlineComponentsBegin(), object->inlineComponentsEnd(), [&](const QV4::CompiledData::InlineComponent &ic) {
+ return ic.objectIndex == icObjectId;
+ });
+ if (icIt != object->inlineComponentsEnd()) {
+ Q_ASSERT(m_inlineComponentToCompiledData.contains(icIt->nameIndex));
+ return m_inlineComponentToCompiledData[icIt->nameIndex].data();
+ }
+ }
+ Q_UNREACHABLE();
+ return nullptr; // make integrity happy
+}
+
void QQmlTypeData::registerCallback(TypeDataCallback *callback)
{
Q_ASSERT(!m_callbacks.contains(callback));
@@ -105,8 +124,10 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback)
Q_ASSERT(!m_callbacks.contains(callback));
}
-QQmlMetaType::CompositeMetaTypeIds QQmlTypeData::typeIds() const
+CompositeMetaTypeIds QQmlTypeData::typeIds(int objectId) const
{
+ if (objectId != 0)
+ return m_inlineComponentData[objectId].typeIds;
return m_typeIds;
}
@@ -135,8 +156,15 @@ bool QQmlTypeData::tryLoadFromDiskCache()
m_compiledData = unit;
- for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
- m_typeReferences.collectFromObject(m_compiledData->objectAt(i));
+ QVector<QV4::CompiledData::InlineComponent> ics;
+ for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i) {
+ auto object = m_compiledData->objectAt(i);
+ m_typeReferences.collectFromObject(object);
+ const auto inlineComponentTable = object->inlineComponentTable();
+ for (auto i = 0; i != object->nInlineComponents; ++i) {
+ ics.push_back(inlineComponentTable[i]);
+ }
+ }
m_importCache.setBaseUrl(finalUrl(), finalUrlString());
@@ -183,6 +211,20 @@ bool QQmlTypeData::tryLoadFromDiskCache()
}
}
+ QQmlType containingType;
+ auto containingTypeName = finalUrl().fileName().split(QLatin1Char('.')).first();
+ int major = -1, minor = -1;
+ QQmlImportNamespace *ns = nullptr;
+ m_importCache.resolveType(containingTypeName, &containingType, &major, &minor, &ns);
+ for (auto&& ic: ics) {
+ QString const nameString = m_compiledData->stringAt(ic.nameIndex);
+ QByteArray const name = nameString.toUtf8();
+ auto importUrl = finalUrl();
+ importUrl.setFragment(QString::number(ic.objectIndex));
+ auto import = new QQmlImportInstance();
+ m_importCache.addInlineComponentImport(import, nameString, importUrl, containingType);
+ }
+
return true;
}
@@ -233,6 +275,36 @@ static bool addTypeReferenceChecksumsToHash(const QList<QQmlTypeData::TypeRefere
return true;
}
+// local helper function for inline components
+namespace {
+template<typename ObjectContainer>
+void setupICs(const ObjectContainer &container, QHash<int, InlineComponentData> *icData, const QUrl &finalUrl) {
+ Q_ASSERT(icData->empty());
+ for (int i = 0; i != container->objectCount(); ++i) {
+ auto root = container->objectAt(i);
+ for (auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) {
+ auto url = finalUrl;
+ url.setFragment(QString::number(it->objectIndex));
+ const QByteArray &className = QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(url);
+ InlineComponentData icDatum(QQmlMetaType::registerInternalCompositeType(className), int(it->objectIndex), int(it->nameIndex), 0, 0, 0);
+ icData->insert(it->objectIndex, icDatum);
+ }
+ }
+};
+}
+
+template<typename Container>
+void QQmlTypeData::setCompileUnit(const Container &container)
+{
+ for (int i = 0; i != container->objectCount(); ++i) {
+ auto const root = container->objectAt(i);
+ for (auto it = root->inlineComponentsBegin(); it != root->inlineComponentsEnd(); ++it) {
+ auto *typeRef = m_compiledData->resolvedType(it->nameIndex);
+ typeRef->compilationUnit = m_compiledData; // share compilation unit
+ }
+ }
+}
+
void QQmlTypeData::done()
{
auto cleanup = qScopeGuard([this]{
@@ -263,10 +335,30 @@ void QQmlTypeData::done()
}
// Check all type dependencies for errors
- for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end;
+ for (auto it = qAsConst(m_resolvedTypes).begin(), end = qAsConst(m_resolvedTypes).end(); it != end;
++it) {
const TypeReference &type = *it;
- Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError());
+ Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError() || type.type.isInlineComponentType());
+ if (type.type.isInlineComponentType() && !type.type.pendingResolutionName().isEmpty()) {
+ auto containingType = type.type.containingType();
+ auto objectId = containingType.lookupInlineComponentIdByName(type.type.pendingResolutionName());
+ if (objectId < 0) { // can be any negative number if we tentatively resolved it in QQmlImport but it actually was not an inline component
+ const QString typeName = stringAt(it.key());
+ int lastDot = typeName.lastIndexOf('.');
+
+ QList<QQmlError> errors = type.typeData ? type.typeData->errors() : QList<QQmlError>{};
+ QQmlError error;
+ error.setUrl(url());
+ error.setLine(type.location.line);
+ error.setColumn(type.location.column);
+ error.setDescription(QQmlTypeLoader::tr("Type %1 has no inline component type called %2").arg(typeName.leftRef(lastDot), type.type.pendingResolutionName()));
+ errors.prepend(error);
+ setError(errors);
+ return;
+ } else {
+ type.type.setInlineComponentObjectId(objectId);
+ }
+ }
if (type.typeData && type.typeData->isError()) {
const QString typeName = stringAt(it.key());
@@ -304,13 +396,23 @@ void QQmlTypeData::done()
m_typeClassName = QQmlPropertyCacheCreatorBase::createClassNameTypeByUrl(finalUrl());
if (!m_typeClassName.isEmpty())
m_typeIds = QQmlMetaType::registerInternalCompositeType(m_typeClassName);
+
+ if (m_document) {
+ setupICs(m_document, &m_inlineComponentData, finalUrl());
+ } else {
+ setupICs(m_compiledData, &m_inlineComponentData, finalUrl());
+ }
auto typeCleanupGuard = qScopeGuard([&]() {
- if (isError() && m_typeIds.isValid())
+ if (isError() && m_typeIds.isValid()) {
QQmlMetaType::unregisterInternalCompositeType(m_typeIds);
+ for (auto&& icData: qAsConst(m_inlineComponentData)) {
+ QQmlMetaType::unregisterInternalCompositeType(icData.typeIds);
+ }
+ }
});
- QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QV4::ResolvedTypeReferenceMap resolvedTypeCache;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
{
QQmlJS::DiagnosticMessage error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
if (error.isValid()) {
@@ -342,8 +444,12 @@ void QQmlTypeData::done()
if (!m_document.isNull()) {
// Compile component
compile(typeNameCache, &resolvedTypeCache, dependencyHasher);
+ if (!isError())
+ setCompileUnit(m_document);
} else {
createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
+ if (!isError())
+ setCompileUnit(m_compiledData);
}
if (isError())
@@ -351,6 +457,7 @@ void QQmlTypeData::done()
{
QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(engine);
+ m_compiledData->inlineComponentData = m_inlineComponentData;
{
// Sanity check property bindings
QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData);
@@ -389,6 +496,26 @@ void QQmlTypeData::done()
}
}
+ // associate inline components to root component
+ {
+ auto typeName = finalUrlString().splitRef('/').last().split('.').first().toString();
+ // typeName can be empty if a QQmlComponent was constructed with an empty QUrl parameter
+ if (!typeName.isEmpty() && typeName.at(0).isUpper() && !m_inlineComponentData.isEmpty()) {
+ QHashedStringRef const hashedStringRef { typeName };
+ QList<QQmlError> errors;
+ auto type = QQmlMetaType::typeForUrl(finalUrlString(), hashedStringRef, false, &errors);
+ Q_ASSERT(errors.empty());
+ if (type.isValid()) {
+ for (auto const &icDatum : m_inlineComponentData) {
+ Q_ASSERT(icDatum.typeIds.isValid());
+ QQmlType existingType = type.lookupInlineComponentById(type.lookupInlineComponentIdByName(m_compiledData->stringAt(icDatum.nameIndex)));
+ type.associateInlineComponent(m_compiledData->stringAt(icDatum.nameIndex),
+ icDatum.objectIndex, icDatum.typeIds, existingType);
+ }
+ }
+ }
+ }
+
{
// Collect imported scripts
m_compiledData->dependentScripts.reserve(m_scripts.count());
@@ -522,6 +649,22 @@ void QQmlTypeData::restoreIR(QV4::CompiledData::CompilationUnit &&unit)
void QQmlTypeData::continueLoadFromIR()
{
+ QQmlType containingType;
+ auto containingTypeName = finalUrl().fileName().split(QLatin1Char('.')).first();
+ int major = -1, minor = -1;
+ QQmlImportNamespace *ns = nullptr;
+ m_importCache.resolveType(containingTypeName, &containingType, &major, &minor, &ns);
+ for (auto const& object: m_document->objects) {
+ for (auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it) {
+ QString const nameString = m_document->stringAt(it->nameIndex);
+ QByteArray const name = nameString.toUtf8();
+ auto importUrl = finalUrl();
+ importUrl.setFragment(QString::number(it->objectIndex));
+ auto import = new QQmlImportInstance(); // Note: The cache takes ownership of the QQmlImportInstance
+ m_importCache.addInlineComponentImport(import, nameString, importUrl, containingType);
+ }
+ }
+
m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
m_importCache.setBaseUrl(finalUrl(), finalUrlString());
@@ -724,6 +867,17 @@ void QQmlTypeData::resolveTypes()
ref.typeData = typeLoader()->getType(ref.type.sourceUrl());
addDependency(ref.typeData.data());
}
+ if (ref.type.isInlineComponentType()) {
+ auto containingType = ref.type.containingType();
+ if (containingType.isValid()) {
+ auto const url = containingType.sourceUrl();
+ if (url.isValid()) {
+ auto typeData = typeLoader()->getType(url);
+ ref.typeData = typeData;
+ addDependency(typeData.data());
+ }
+ }
+ }
ref.majorVersion = majorVersion;
ref.minorVersion = minorVersion;
@@ -731,7 +885,6 @@ void QQmlTypeData::resolveTypes()
ref.location.column = unresolvedRef->location.column;
ref.needsCreation = unresolvedRef->needsCreation;
-
m_resolvedTypes.insert(unresolvedRef.key(), ref);
}
@@ -766,6 +919,38 @@ QQmlJS::DiagnosticMessage QQmlTypeData::buildTypeResolutionCaches(
return qQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType.qmlTypeName()));
}
ref->compilationUnit = resolvedType->typeData->compilationUnit();
+ if (resolvedType->type.isInlineComponentType()) {
+ // Inline component which is part of an already resolved type
+ int objectId = -1;
+ if (qmlType.containingType().isValid()) {
+ objectId = qmlType.containingType().lookupInlineComponentIdByName(QString::fromUtf8(qmlType.typeName()));
+ qmlType.setInlineComponentObjectId(objectId);
+ } else {
+ objectId = resolvedType->type.inlineComponendId();
+ }
+ Q_ASSERT(objectId != -1);
+ ref->typePropertyCache = resolvedType->typeData->compilationUnit()->propertyCaches.at(objectId);
+ ref->type = qmlType;
+ Q_ASSERT(ref->type.isInlineComponentType());
+ }
+ } else if (resolvedType->type.isInlineComponentType()) {
+ // Inline component, defined in the file we are currently compiling
+ if (!m_inlineComponentToCompiledData.contains(resolvedType.key())) {
+ ref->type = qmlType;
+ if (qmlType.isValid()) {
+ // this is required for inline components in singletons
+ auto typeID = qmlType.lookupInlineComponentById(qmlType.inlineComponendId()).typeId();
+ auto exUnit = engine->obtainExecutableCompilationUnit(typeID);
+ if (exUnit) {
+ ref->compilationUnit = exUnit;
+ ref->typePropertyCache = engine->propertyCacheForType(typeID);
+ }
+ }
+ } else {
+ ref->compilationUnit = m_inlineComponentToCompiledData[resolvedType.key()];
+ ref->typePropertyCache = m_inlineComponentToCompiledData[resolvedType.key()]->rootPropertyCache();
+ }
+
} else if (qmlType.isValid() && !resolvedType->selfReference) {
ref->type = qmlType;
Q_ASSERT(ref->type.isValid());
diff --git a/src/qml/qml/qqmltypedata_p.h b/src/qml/qml/qqmltypedata_p.h
index 53e78e06d7..d894090b36 100644
--- a/src/qml/qml/qqmltypedata_p.h
+++ b/src/qml/qml/qqmltypedata_p.h
@@ -86,6 +86,8 @@ private:
friend class QQmlTypeLoader;
QQmlTypeData(const QUrl &, QQmlTypeLoader *);
+ template<typename Container>
+ void setCompileUnit(const Container &container);
public:
~QQmlTypeData() override;
@@ -93,6 +95,7 @@ public:
const QList<ScriptReference> &resolvedScripts() const;
QV4::ExecutableCompilationUnit *compilationUnit() const;
+ QV4::ExecutableCompilationUnit *compilationUnitForInlineComponent(unsigned int icObjectId) const;
// Used by QQmlComponent to get notifications
struct TypeDataCallback {
@@ -103,7 +106,7 @@ public:
void registerCallback(TypeDataCallback *);
void unregisterCallback(TypeDataCallback *);
- QQmlMetaType::CompositeMetaTypeIds typeIds() const;
+ CompositeMetaTypeIds typeIds(int objectId = 0) const;
QByteArray typeClassName() const { return m_typeClassName; }
protected:
@@ -155,10 +158,15 @@ private:
bool m_typesResolved:1;
// Used for self-referencing types, otherwise -1.
- QQmlMetaType::CompositeMetaTypeIds m_typeIds;
+ CompositeMetaTypeIds m_typeIds;
QByteArray m_typeClassName; // used for meta-object later
- QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compiledData;
+ using ExecutableCompilationUnitPtr = QQmlRefPointer<QV4::ExecutableCompilationUnit>;
+
+ QHash<int, InlineComponentData> m_inlineComponentData;
+
+ ExecutableCompilationUnitPtr m_compiledData;
+ QHash<int, ExecutableCompilationUnitPtr> m_inlineComponentToCompiledData;
QList<TypeDataCallback *> m_callbacks;
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 2d3c03cedb..02032142ee 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -1332,6 +1332,41 @@ ReturnedValue QtObject::method_createComponent(const FunctionObject *b, const Va
return QV4::QObjectWrapper::wrap(scope.engine, c);
}
+ReturnedValue QtObject::method_get_uiLanguage(const FunctionObject *b, const Value * /*thisObject*/, const Value * /*argv*/, int /*argc*/)
+{
+ QV4::Scope scope(b);
+ QJSEngine *jsEngine = scope.engine->jsEngine();
+ if (!jsEngine)
+ return Encode::null();
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(scope.engine);
+ if (ep && ep->propertyCapture) {
+ static int propertyIndex = -1;
+ static int notifySignalIndex = -1;
+ if (propertyIndex < 0) {
+ QMetaProperty metaProperty =
+ QQmlEngine::staticMetaObject.property(QQmlEngine::staticMetaObject.indexOfProperty("uiLanguage"));
+ propertyIndex = metaProperty.propertyIndex();
+ notifySignalIndex = metaProperty.notifySignalIndex();
+ }
+ ep->propertyCapture->captureProperty(QQmlEnginePrivate::get(ep), propertyIndex, notifySignalIndex);
+ }
+
+ return Encode(scope.engine->newString(QJSEnginePrivate::get(jsEngine)->uiLanguage));
+}
+
+ReturnedValue QtObject::method_set_uiLanguage(const FunctionObject *b, const Value * /*thisObject*/, const Value *argv, int argc)
+{
+ Scope scope(b);
+ if (!argc)
+ THROW_TYPE_ERROR();
+ QJSEngine *jsEngine = scope.engine->jsEngine();
+ if (!jsEngine)
+ THROW_TYPE_ERROR();
+ jsEngine->setUiLanguage(argv[0].toQString());
+ return Encode::undefined();
+}
+
#if QT_CONFIG(qml_locale)
/*!
\qmlmethod Qt::locale(name)
@@ -1829,6 +1864,14 @@ void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions ext
globalObject->defineDefaultProperty(QStringLiteral("qsTrId"), QV4::GlobalExtensions::method_qsTrId);
globalObject->defineDefaultProperty(QStringLiteral("QT_TRID_NOOP"), QV4::GlobalExtensions::method_qsTrIdNoOp);
+ ScopedString qtName(scope, v4->newString(QStringLiteral("Qt")));
+ ScopedObject qt(scope, globalObject->get(qtName));
+ if (!qt) {
+ qt = v4->newObject();
+ globalObject->defineDefaultProperty(qtName, qt);
+ }
+ qt->defineAccessorProperty(QStringLiteral("uiLanguage"), QV4::QtObject::method_get_uiLanguage, QV4::QtObject::method_set_uiLanguage);
+
// string prototype extension
scope.engine->stringPrototype()->defineDefaultProperty(QStringLiteral("arg"), QV4::GlobalExtensions::method_string_arg);
#endif
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index d87b83ba10..5cbb52471d 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -126,6 +126,8 @@ struct QtObject : Object
static ReturnedValue method_resolvedUrl(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_createQmlObject(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_createComponent(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_get_uiLanguage(const FunctionObject *b, const Value *, const Value *, int);
+ static ReturnedValue method_set_uiLanguage(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
#if QT_CONFIG(qml_locale)
static ReturnedValue method_locale(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc);
#endif
diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp
index d5ab267cec..f3a6fea193 100644
--- a/src/qmltest/quicktestresult.cpp
+++ b/src/qmltest/quicktestresult.cpp
@@ -480,7 +480,7 @@ static QString qtestFixUrl(const QUrl &location)
void QuickTestResult::fail
(const QString &message, const QUrl &location, int line)
{
- QTestResult::addFailure(message.toLatin1().constData(),
+ QTestResult::addFailure(message.toUtf8().constData(),
qtestFixUrl(location).toLatin1().constData(), line);
}
@@ -493,7 +493,7 @@ bool QuickTestResult::verify
qtestFixUrl(location).toLatin1().constData(), line);
} else {
return QTestResult::verify
- (success, message.toLatin1().constData(), "",
+ (success, message.toUtf8().constData(), "",
qtestFixUrl(location).toLatin1().constData(), line);
}
}
@@ -601,7 +601,7 @@ bool QuickTestResult::compare
const QUrl &location, int line)
{
return QTestResult::compare
- (success, message.toLocal8Bit().constData(),
+ (success, message.toUtf8().constData(),
QTest::toString(val1.toString().toLatin1().constData()),
QTest::toString(val2.toString().toLatin1().constData()),
"", "",
@@ -611,7 +611,7 @@ bool QuickTestResult::compare
void QuickTestResult::skip
(const QString &message, const QUrl &location, int line)
{
- QTestResult::addSkip(message.toLatin1().constData(),
+ QTestResult::addSkip(message.toUtf8().constData(),
qtestFixUrl(location).toLatin1().constData(), line);
QTestResult::setSkipCurrentTest(true);
}
@@ -630,13 +630,13 @@ bool QuickTestResult::expectFailContinue
{
return QTestResult::expectFail
(tag.toLatin1().constData(),
- QTest::toString(comment.toLatin1().constData()),
+ QTest::toString(comment.toUtf8().constData()),
QTest::Continue, qtestFixUrl(location).toLatin1().constData(), line);
}
void QuickTestResult::warn(const QString &message, const QUrl &location, int line)
{
- QTestLog::warn(message.toLatin1().constData(), qtestFixUrl(location).toLatin1().constData(), line);
+ QTestLog::warn(message.toUtf8().constData(), qtestFixUrl(location).toLatin1().constData(), line);
}
void QuickTestResult::ignoreWarning(const QJSValue &message)
@@ -646,7 +646,7 @@ void QuickTestResult::ignoreWarning(const QJSValue &message)
QTestLog::ignoreMessage(QtWarningMsg, message.toVariant().toRegularExpression());
#endif
} else {
- QTestLog::ignoreMessage(QtWarningMsg, message.toString().toLatin1());
+ QTestLog::ignoreMessage(QtWarningMsg, message.toString().toUtf8());
}
}
diff --git a/src/qmlworkerscript/qquickworkerscript.cpp b/src/qmlworkerscript/qquickworkerscript.cpp
index 72ae6d5bd4..4a79027234 100644
--- a/src/qmlworkerscript/qquickworkerscript.cpp
+++ b/src/qmlworkerscript/qquickworkerscript.cpp
@@ -544,7 +544,7 @@ void QQuickWorkerScript::setSource(const QUrl &source)
}
/*!
- \qmlproperty url WorkerScript::ready
+ \qmlproperty bool WorkerScript::ready
This holds whether the WorkerScript has been initialized and is ready
for receiving messages via \tt WorkerScript.sendMessage().
diff --git a/src/quick/configure.json b/src/quick/configure.json
index 6cd3099a20..fbb70fe572 100644
--- a/src/quick/configure.json
+++ b/src/quick/configure.json
@@ -116,7 +116,7 @@
"label": "Path support",
"purpose": "Provides Path elements.",
"section": "Qt Quick",
- "condition": "features.quick-shadereffect",
+ "condition": "module.gui",
"output": [
"privateFeature"
]
diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp
index edd3805d7c..32407a474f 100644
--- a/src/quick/items/qquickborderimage.cpp
+++ b/src/quick/items/qquickborderimage.cpp
@@ -168,6 +168,7 @@ QT_BEGIN_NAMESPACE
QQuickBorderImage::QQuickBorderImage(QQuickItem *parent)
: QQuickImageBase(*(new QQuickBorderImagePrivate), parent)
{
+ connect(this, &QQuickImageBase::sourceSizeChanged, this, &QQuickBorderImage::sourceSizeChanged);
}
QQuickBorderImage::~QQuickBorderImage()
@@ -295,20 +296,7 @@ void QQuickBorderImage::load()
Q_D(QQuickBorderImage);
if (d->url.isEmpty()) {
- d->pix.clear(this);
- d->status = Null;
- setImplicitSize(0, 0);
- emit statusChanged(d->status);
- if (d->progress != 0.0) {
- d->progress = 0.0;
- emit progressChanged(d->progress);
- }
- if (sourceSize() != d->oldSourceSize) {
- d->oldSourceSize = sourceSize();
- emit sourceSizeChanged();
- }
- pixmapChange();
- return;
+ loadEmptyUrl();
} else {
if (d->url.path().endsWith(QLatin1String("sci"))) {
QString lf = QQmlFile::urlToLocalFileOrQrc(d->url);
@@ -316,7 +304,6 @@ void QQuickBorderImage::load()
QFile file(lf);
file.open(QIODevice::ReadOnly);
setGridScaledImage(QQuickGridScaledImage(&file));
- return;
} else {
#if QT_CONFIG(qml_network)
if (d->progress != 0.0) {
@@ -328,50 +315,13 @@ void QQuickBorderImage::load()
d->sciReply = qmlEngine(this)->networkAccessManager()->get(req);
qmlobject_connect(d->sciReply, QNetworkReply, SIGNAL(finished()),
this, QQuickBorderImage, SLOT(sciRequestFinished()));
+ emit statusChanged(d->status);
#endif
}
} else {
- QQuickPixmap::Options options;
- if (d->async)
- options |= QQuickPixmap::Asynchronous;
- if (d->cache)
- options |= QQuickPixmap::Cache;
- d->pix.clear(this);
-
- const qreal targetDevicePixelRatio = (window() ? window()->effectiveDevicePixelRatio() : qGuiApp->devicePixelRatio());
- d->devicePixelRatio = 1.0;
-
- QUrl loadUrl = d->url;
- resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
- d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, QQuickImageProviderOptions(), d->currentFrame, d->frameCount);
-
- if (d->pix.isLoading()) {
- if (d->progress != 0.0) {
- d->progress = 0.0;
- emit progressChanged(d->progress);
- }
- d->status = Loading;
-
- static int thisRequestProgress = -1;
- static int thisRequestFinished = -1;
- if (thisRequestProgress == -1) {
- thisRequestProgress =
- QQuickImageBase::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
- thisRequestFinished =
- QQuickImageBase::staticMetaObject.indexOfSlot("requestFinished()");
- }
- d->pix.connectFinished(this, thisRequestFinished);
- d->pix.connectDownloadProgress(this, thisRequestProgress);
-
- update(); //pixmap may have invalidated texture, updatePaintNode needs to be called before the next repaint
- } else {
- requestFinished();
- return;
- }
+ loadPixmap(d->url, LoadPixmapOptions(HandleDPR | UseProviderOptions));
}
}
-
- emit statusChanged(d->status);
}
/*!
@@ -472,39 +422,7 @@ void QQuickBorderImage::setGridScaledImage(const QQuickGridScaledImage& sci)
d->verticalTileMode = sci.verticalTileRule();
d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl()));
-
- QQuickPixmap::Options options;
- if (d->async)
- options |= QQuickPixmap::Asynchronous;
- if (d->cache)
- options |= QQuickPixmap::Cache;
- d->pix.clear(this);
- d->pix.load(qmlEngine(this), d->sciurl, options);
-
- if (d->pix.isLoading()) {
- if (d->progress != 0.0) {
- d->progress = 0.0;
- emit progressChanged(d->progress);
- }
- if (d->status != Loading) {
- d->status = Loading;
- emit statusChanged(d->status);
- }
- static int thisRequestProgress = -1;
- static int thisRequestFinished = -1;
- if (thisRequestProgress == -1) {
- thisRequestProgress =
- QQuickBorderImage::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
- thisRequestFinished =
- QQuickBorderImage::staticMetaObject.indexOfSlot("requestFinished()");
- }
-
- d->pix.connectFinished(this, thisRequestFinished);
- d->pix.connectDownloadProgress(this, thisRequestProgress);
-
- } else {
- requestFinished();
- }
+ loadPixmap(d->sciurl);
}
}
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 8bab14bfd1..55b29d7a70 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -241,46 +241,47 @@ int QQuickImageBase::frameCount() const
return d->frameCount;
}
-void QQuickImageBase::load()
+void QQuickImageBase::loadEmptyUrl()
{
Q_D(QQuickImageBase);
+ d->pix.clear(this);
+ if (d->progress != 0.0) {
+ d->progress = 0.0;
+ emit progressChanged(d->progress);
+ }
+ d->status = Null;
+ setImplicitSize(0, 0); // also called in QQuickImageBase::pixmapChange, but not QQuickImage/QQuickBorderImage overrides
+ pixmapChange(); // This calls update() in QQuickBorderImage and QQuickImage, not in QQuickImageBase...
- if (d->url.isEmpty()) {
- d->pix.clear(this);
- if (d->progress != 0.0) {
- d->progress = 0.0;
- emit progressChanged(d->progress);
- }
- pixmapChange();
- d->status = Null;
- emit statusChanged(d->status);
-
- if (sourceSize() != d->oldSourceSize) {
- d->oldSourceSize = sourceSize();
- emit sourceSizeChanged();
- }
- if (autoTransform() != d->oldAutoTransform) {
- d->oldAutoTransform = autoTransform();
- emitAutoTransformBaseChanged();
- }
- update();
-
- } else {
- QQuickPixmap::Options options;
- if (d->async)
- options |= QQuickPixmap::Asynchronous;
- if (d->cache)
- options |= QQuickPixmap::Cache;
- d->pix.clear(this);
+ emit statusChanged(d->status);
+ if (sourceSize() != d->oldSourceSize) {
+ d->oldSourceSize = sourceSize();
+ emit sourceSizeChanged();
+ }
+ if (autoTransform() != d->oldAutoTransform) {
+ d->oldAutoTransform = autoTransform();
+ emitAutoTransformBaseChanged();
+ }
+ update(); // .. but double updating should be harmless
+}
+void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
+{
+ Q_D(QQuickImageBase);
+ QQuickPixmap::Options options;
+ if (d->async)
+ options |= QQuickPixmap::Asynchronous;
+ if (d->cache)
+ options |= QQuickPixmap::Cache;
+ d->pix.clear(this);
+ QUrl loadUrl = url;
+ QQmlEngine* engine = qmlEngine(this);
+ if (engine && engine->urlInterceptor())
+ loadUrl = engine->urlInterceptor()->intercept(loadUrl, QQmlAbstractUrlInterceptor::UrlString);
+
+ if (loadOptions & HandleDPR) {
const qreal targetDevicePixelRatio = (window() ? window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio());
d->devicePixelRatio = 1.0;
-
- QUrl loadUrl = d->url;
- QQmlEngine* engine = qmlEngine(this);
- if (engine && engine->urlInterceptor())
- loadUrl = engine->urlInterceptor()->intercept(loadUrl, QQmlAbstractUrlInterceptor::UrlString);
-
bool updatedDevicePixelRatio = false;
if (d->sourcesize.isValid())
updatedDevicePixelRatio = d->updateDevicePixelRatio(targetDevicePixelRatio);
@@ -290,34 +291,51 @@ void QQuickImageBase::load()
// an "@2x" file is found.
resolve2xLocalFile(d->url, targetDevicePixelRatio, &loadUrl, &d->devicePixelRatio);
}
+ }
+
+ d->pix.load(qmlEngine(this),
+ loadUrl,
+ (loadOptions & HandleDPR) ? d->sourcesize * d->devicePixelRatio : QSize(),
+ options,
+ (loadOptions & UseProviderOptions) ? d->providerOptions : QQuickImageProviderOptions(),
+ d->currentFrame, d->frameCount);
+
+ if (d->pix.isLoading()) {
+ if (d->progress != 0.0) {
+ d->progress = 0.0;
+ emit progressChanged(d->progress);
+ }
+ if (d->status != Loading) {
+ d->status = Loading;
+ emit statusChanged(d->status);
+ }
- d->pix.load(qmlEngine(this), loadUrl, d->sourcesize * d->devicePixelRatio, options, d->providerOptions, d->currentFrame, d->frameCount);
-
- if (d->pix.isLoading()) {
- if (d->progress != 0.0) {
- d->progress = 0.0;
- emit progressChanged(d->progress);
- }
- if (d->status != Loading) {
- d->status = Loading;
- emit statusChanged(d->status);
- }
-
- static int thisRequestProgress = -1;
- static int thisRequestFinished = -1;
- if (thisRequestProgress == -1) {
- thisRequestProgress =
- QQuickImageBase::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
- thisRequestFinished =
- QQuickImageBase::staticMetaObject.indexOfSlot("requestFinished()");
- }
-
- d->pix.connectFinished(this, thisRequestFinished);
- d->pix.connectDownloadProgress(this, thisRequestProgress);
- update(); //pixmap may have invalidated texture, updatePaintNode needs to be called before the next repaint
- } else {
- requestFinished();
+ static int thisRequestProgress = -1;
+ static int thisRequestFinished = -1;
+ if (thisRequestProgress == -1) {
+ thisRequestProgress =
+ QQuickImageBase::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)");
+ thisRequestFinished =
+ QQuickImageBase::staticMetaObject.indexOfSlot("requestFinished()");
}
+
+ d->pix.connectFinished(this, thisRequestFinished);
+ d->pix.connectDownloadProgress(this, thisRequestProgress);
+ update(); //pixmap may have invalidated texture, updatePaintNode needs to be called before the next repaint
+ } else {
+ requestFinished();
+ }
+}
+
+void QQuickImageBase::load()
+{
+ Q_D(QQuickImageBase);
+
+ if (d->url.isEmpty()) {
+ loadEmptyUrl();
+ update();
+ } else {
+ loadPixmap(d->url, LoadPixmapOptions(HandleDPR | UseProviderOptions));
}
}
diff --git a/src/quick/items/qquickimagebase_p.h b/src/quick/items/qquickimagebase_p.h
index d1d01ad27d..9308230bfa 100644
--- a/src/quick/items/qquickimagebase_p.h
+++ b/src/quick/items/qquickimagebase_p.h
@@ -76,6 +76,15 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImageBase : public QQuickImplicitSizeItem
QML_UNCREATABLE("ImageBase is an abstract base class.")
public:
+ enum LoadPixmapOption {
+ NoOption = 0x0000,
+ HandleDPR = 0x0001,
+ UseProviderOptions = 0x0002
+ };
+
+ Q_DECLARE_FLAGS(LoadPixmapOptions, LoadPixmapOption)
+ Q_FLAG(LoadPixmapOptions)
+
QQuickImageBase(QQuickItem *parent=nullptr);
~QQuickImageBase();
enum Status { Null, Ready, Loading, Error };
@@ -127,6 +136,8 @@ Q_SIGNALS:
Q_REVISION(14) void frameCountChanged();
protected:
+ void loadEmptyUrl();
+ void loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions = NoOption);
virtual void load();
void componentComplete() override;
virtual void pixmapChange();
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index b5932c6f80..03cdeb5bef 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -74,6 +74,7 @@
#include <private/qv4object_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qdebug_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
#if QT_CONFIG(cursor)
# include <QtGui/qcursor.h>
@@ -4475,9 +4476,94 @@ void QQuickItem::polish()
}
}
+static bool unwrapMapFromToFromItemArgs(QQmlV4Function *args, const QQuickItem *itemForWarning, const QString &functionNameForWarning,
+ QQuickItem **itemObj, qreal *x, qreal *y, qreal *w, qreal *h, bool *isRect)
+{
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ if (args->length() != 2 && args->length() != 3 && args->length() != 5) {
+ v4->throwTypeError();
+ return false;
+ }
+
+ QV4::Scope scope(v4);
+ QV4::ScopedValue item(scope, (*args)[0]);
+
+ *itemObj = nullptr;
+ if (!item->isNull()) {
+ QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, item->as<QV4::QObjectWrapper>());
+ if (qobjectWrapper)
+ *itemObj = qobject_cast<QQuickItem*>(qobjectWrapper->object());
+ }
+
+ if (!(*itemObj) && !item->isNull()) {
+ qmlWarning(itemForWarning) << functionNameForWarning << " given argument \"" << item->toQStringNoThrow()
+ << "\" which is neither null nor an Item";
+ v4->throwTypeError();
+ return false;
+ }
+
+ *isRect = false;
+
+ if (args->length() == 2) {
+ QV4::ScopedValue sv(scope, (*args)[1]);
+ if (sv->isNull()) {
+ qmlWarning(itemForWarning) << functionNameForWarning << "given argument \"" << sv->toQStringNoThrow()
+ << "\" which is neither a point nor a rect";
+ v4->throwTypeError();
+ return false;
+ }
+ const QV4::Scoped<QV4::QQmlValueTypeWrapper> variantWrapper(scope, sv->as<QV4::QQmlValueTypeWrapper>());
+ const QVariant v = variantWrapper ? variantWrapper->toVariant() : QVariant();
+ if (v.canConvert<QPointF>()) {
+ const QPointF p = v.toPointF();
+ *x = p.x();
+ *y = p.y();
+ } else if (v.canConvert<QRectF>()) {
+ const QRectF r = v.toRectF();
+ *x = r.x();
+ *y = r.y();
+ *w = r.width();
+ *h = r.height();
+ *isRect = true;
+ } else {
+ qmlWarning(itemForWarning) << functionNameForWarning << "given argument \"" << sv->toQStringNoThrow()
+ << "\" which is neither a point nor a rect";
+ v4->throwTypeError();
+ return false;
+ }
+ } else {
+ QV4::ScopedValue vx(scope, (*args)[1]);
+ QV4::ScopedValue vy(scope, (*args)[2]);
+
+ if (!vx->isNumber() || !vy->isNumber()) {
+ v4->throwTypeError();
+ return false;
+ }
+
+ *x = vx->asDouble();
+ *y = vy->asDouble();
+
+ if (args->length() > 3) {
+ QV4::ScopedValue vw(scope, (*args)[3]);
+ QV4::ScopedValue vh(scope, (*args)[4]);
+ if (!vw->isNumber() || !vh->isNumber()) {
+ v4->throwTypeError();
+ return false;
+ }
+ *w = vw->asDouble();
+ *h = vh->asDouble();
+ *isRect = true;
+ }
+ }
+
+ return true;
+}
+
/*!
\qmlmethod object QtQuick::Item::mapFromItem(Item item, real x, real y)
+ \qmlmethod object QtQuick::Item::mapFromItem(Item item, point p)
\qmlmethod object QtQuick::Item::mapFromItem(Item item, real x, real y, real width, real height)
+ \qmlmethod object QtQuick::Item::mapFromItem(Item item, rect r)
Maps the point (\a x, \a y) or rect (\a x, \a y, \a width, \a height), which is in \a
item's coordinate system, to this item's coordinate system, and returns a \l point or \l rect
@@ -4487,6 +4573,8 @@ void QQuickItem::polish()
If \a item is a \c null value, this maps the point or rect from the coordinate system of
the root QML view.
+
+ The versions accepting point and rect are since Qt 5.15.
*/
/*!
\internal
@@ -4494,55 +4582,16 @@ void QQuickItem::polish()
void QQuickItem::mapFromItem(QQmlV4Function *args) const
{
QV4::ExecutionEngine *v4 = args->v4engine();
- if (args->length() != 3 && args->length() != 5) {
- v4->throwTypeError();
- return;
- }
-
QV4::Scope scope(v4);
- QV4::ScopedValue item(scope, (*args)[0]);
-
- QQuickItem *itemObj = nullptr;
- if (!item->isNull()) {
- QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, item->as<QV4::QObjectWrapper>());
- if (qobjectWrapper)
- itemObj = qobject_cast<QQuickItem*>(qobjectWrapper->object());
- }
- if (!itemObj && !item->isNull()) {
- qmlWarning(this) << "mapFromItem() given argument \"" << item->toQStringNoThrow()
- << "\" which is neither null nor an Item";
- v4->throwTypeError();
- return;
- }
-
- QV4::ScopedValue vx(scope, (*args)[1]);
- QV4::ScopedValue vy(scope, (*args)[2]);
-
- if (!vx->isNumber() || !vy->isNumber()) {
- v4->throwTypeError();
+ qreal x, y, w, h;
+ bool isRect;
+ QQuickItem *itemObj;
+ if (!unwrapMapFromToFromItemArgs(args, this, QStringLiteral("mapFromItem()"), &itemObj, &x, &y, &w, &h, &isRect))
return;
- }
-
- qreal x = vx->asDouble();
- qreal y = vy->asDouble();
-
- QVariant result;
-
- if (args->length() > 3) {
- QV4::ScopedValue vw(scope, (*args)[3]);
- QV4::ScopedValue vh(scope, (*args)[4]);
- if (!vw->isNumber() || !vh->isNumber()) {
- v4->throwTypeError();
- return;
- }
- qreal w = vw->asDouble();
- qreal h = vh->asDouble();
- result = mapRectFromItem(itemObj, QRectF(x, y, w, h));
- } else {
- result = mapFromItem(itemObj, QPointF(x, y));
- }
+ const QVariant result = isRect ? QVariant(mapRectFromItem(itemObj, QRectF(x, y, w, h)))
+ : QVariant(mapFromItem(itemObj, QPointF(x, y)));
QV4::ScopedObject rv(scope, v4->fromVariant(result));
args->setReturnValue(rv.asReturnedValue());
@@ -4567,7 +4616,9 @@ QTransform QQuickItem::itemTransform(QQuickItem *other, bool *ok) const
/*!
\qmlmethod object QtQuick::Item::mapToItem(Item item, real x, real y)
+ \qmlmethod object QtQuick::Item::mapToItem(Item item, point p)
\qmlmethod object QtQuick::Item::mapToItem(Item item, real x, real y, real width, real height)
+ \qmlmethod object QtQuick::Item::mapToItem(Item item, rect r)
Maps the point (\a x, \a y) or rect (\a x, \a y, \a width, \a height), which is in this
item's coordinate system, to \a item's coordinate system, and returns a \l point or \l rect
@@ -4577,6 +4628,8 @@ QTransform QQuickItem::itemTransform(QQuickItem *other, bool *ok) const
If \a item is a \c null value, this maps the point or rect to the coordinate system of the
root QML view.
+
+ The versions accepting point and rect are since Qt 5.15.
*/
/*!
\internal
@@ -4584,58 +4637,65 @@ QTransform QQuickItem::itemTransform(QQuickItem *other, bool *ok) const
void QQuickItem::mapToItem(QQmlV4Function *args) const
{
QV4::ExecutionEngine *v4 = args->v4engine();
- if (args->length() != 3 && args->length() != 5) {
- v4->throwTypeError();
- return;
- }
-
QV4::Scope scope(v4);
- QV4::ScopedValue item(scope, (*args)[0]);
- QQuickItem *itemObj = nullptr;
- if (!item->isNull()) {
- QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, item->as<QV4::QObjectWrapper>());
- if (qobjectWrapper)
- itemObj = qobject_cast<QQuickItem*>(qobjectWrapper->object());
- }
-
- if (!itemObj && !item->isNull()) {
- qmlWarning(this) << "mapToItem() given argument \"" << item->toQStringNoThrow()
- << "\" which is neither null nor an Item";
- v4->throwTypeError();
+ qreal x, y, w, h;
+ bool isRect;
+ QQuickItem *itemObj;
+ if (!unwrapMapFromToFromItemArgs(args, this, QStringLiteral("mapToItem()"), &itemObj, &x, &y, &w, &h, &isRect))
return;
- }
- QV4::ScopedValue vx(scope, (*args)[1]);
- QV4::ScopedValue vy(scope, (*args)[2]);
+ const QVariant result = isRect ? QVariant(mapRectToItem(itemObj, QRectF(x, y, w, h)))
+ : QVariant(mapToItem(itemObj, QPointF(x, y)));
+
+ QV4::ScopedObject rv(scope, v4->fromVariant(result));
+ args->setReturnValue(rv.asReturnedValue());
+}
- if (!vx->isNumber() || !vy->isNumber()) {
+static bool unwrapMapFromToFromGlobalArgs(QQmlV4Function *args, const QQuickItem *itemForWarning, const QString &functionNameForWarning, qreal *x, qreal *y)
+{
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ if (args->length() != 1 && args->length() != 2) {
v4->throwTypeError();
- return;
+ return false;
}
- qreal x = vx->asDouble();
- qreal y = vy->asDouble();
+ QV4::Scope scope(v4);
- QVariant result;
+ if (args->length() == 1) {
+ QV4::ScopedValue sv(scope, (*args)[0]);
+ if (sv->isNull()) {
+ qmlWarning(itemForWarning) << functionNameForWarning << "given argument \"" << sv->toQStringNoThrow()
+ << "\" which is not a point";
+ v4->throwTypeError();
+ return false;
+ }
+ const QV4::Scoped<QV4::QQmlValueTypeWrapper> variantWrapper(scope, sv->as<QV4::QQmlValueTypeWrapper>());
+ const QVariant v = variantWrapper ? variantWrapper->toVariant() : QVariant();
+ if (v.canConvert<QPointF>()) {
+ const QPointF p = v.toPointF();
+ *x = p.x();
+ *y = p.y();
+ } else {
+ qmlWarning(itemForWarning) << functionNameForWarning << "given argument \"" << sv->toQStringNoThrow()
+ << "\" which is not a point";
+ v4->throwTypeError();
+ return false;
+ }
+ } else {
+ QV4::ScopedValue vx(scope, (*args)[0]);
+ QV4::ScopedValue vy(scope, (*args)[1]);
- if (args->length() > 3) {
- QV4::ScopedValue vw(scope, (*args)[3]);
- QV4::ScopedValue vh(scope, (*args)[4]);
- if (!vw->isNumber() || !vh->isNumber()) {
+ if (!vx->isNumber() || !vy->isNumber()) {
v4->throwTypeError();
- return;
+ return false;
}
- qreal w = vw->asDouble();
- qreal h = vh->asDouble();
- result = mapRectToItem(itemObj, QRectF(x, y, w, h));
- } else {
- result = mapToItem(itemObj, QPointF(x, y));
+ *x = vx->asDouble();
+ *y = vy->asDouble();
}
- QV4::ScopedObject rv(scope, v4->fromVariant(result));
- args->setReturnValue(rv.asReturnedValue());
+ return true;
}
/*!
@@ -4653,22 +4713,12 @@ void QQuickItem::mapToItem(QQmlV4Function *args) const
void QQuickItem::mapFromGlobal(QQmlV4Function *args) const
{
QV4::ExecutionEngine *v4 = args->v4engine();
- if (args->length() != 2) {
- v4->throwTypeError();
- return;
- }
-
QV4::Scope scope(v4);
- QV4::ScopedValue vx(scope, (*args)[0]);
- QV4::ScopedValue vy(scope, (*args)[1]);
- if (!vx->isNumber() || !vy->isNumber()) {
- v4->throwTypeError();
+ qreal x, y;
+ if (!unwrapMapFromToFromGlobalArgs(args, this, QStringLiteral("mapFromGlobal()"), &x, &y))
return;
- }
- qreal x = vx->asDouble();
- qreal y = vy->asDouble();
QVariant result = mapFromGlobal(QPointF(x, y));
QV4::ScopedObject rv(scope, v4->fromVariant(result));
@@ -4690,22 +4740,12 @@ void QQuickItem::mapFromGlobal(QQmlV4Function *args) const
void QQuickItem::mapToGlobal(QQmlV4Function *args) const
{
QV4::ExecutionEngine *v4 = args->v4engine();
- if (args->length() != 2) {
- v4->throwTypeError();
- return;
- }
-
QV4::Scope scope(v4);
- QV4::ScopedValue vx(scope, (*args)[0]);
- QV4::ScopedValue vy(scope, (*args)[1]);
- if (!vx->isNumber() || !vy->isNumber()) {
- v4->throwTypeError();
+ qreal x, y;
+ if (!unwrapMapFromToFromGlobalArgs(args, this, QStringLiteral("mapFromGlobal()"), &x, &y))
return;
- }
- qreal x = vx->asDouble();
- qreal y = vy->asDouble();
QVariant result = mapToGlobal(QPointF(x, y));
QV4::ScopedObject rv(scope, v4->fromVariant(result));
diff --git a/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb b/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
index c49cf9a6d8..c493996375 100644
--- a/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/24bittextmask.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
index f5b3cf91e5..3f8489bfe6 100644
--- a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb b/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
index 3e0731802d..f721207325 100644
--- a/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
index 51cfa99402..93ac0124be 100644
--- a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag.qsb b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag.qsb
index aecf6ef18d..33de256615 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsb b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsb
index e62ec89964..018f5aa07e 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag.qsb
index c6e5d2d102..f64d7ac315 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag.qsb b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag.qsb
index bf6e902f5a..31f870df23 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsb b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsb
index 398b6adaa2..df7ef28add 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag.qsb
index e243f3300a..a90beea1b3 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldtext.frag.qsb b/src/quick/scenegraph/shaders_ng/distancefieldtext.frag.qsb
index 504d586915..a219eb5800 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldtext.vert.qsb b/src/quick/scenegraph/shaders_ng/distancefieldtext.vert.qsb
index f020de9f8c..0cfdfed5a9 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag.qsb
index 0c80f6dbc4..a3998ad695 100644
--- a/src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/distancefieldtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/flatcolor.frag.qsb b/src/quick/scenegraph/shaders_ng/flatcolor.frag.qsb
index 7bc588b806..62ffe0385e 100644
--- a/src/quick/scenegraph/shaders_ng/flatcolor.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/flatcolor.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/flatcolor.vert.qsb b/src/quick/scenegraph/shaders_ng/flatcolor.vert.qsb
index 7ad211c5cf..3f23fa0da1 100644
--- a/src/quick/scenegraph/shaders_ng/flatcolor.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/flatcolor.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag.qsb b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag.qsb
index 3d31b99fca..82e302baa2 100644
--- a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.vert.qsb b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.vert.qsb
index 82b4a63b65..39281bbda5 100644
--- a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag.qsb
index ab27f73163..8ca627e6c1 100644
--- a/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag.qsb b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag.qsb
index 9fae9961c7..b05b62e968 100644
--- a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.vert.qsb b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.vert.qsb
index 53c8c3ef48..92dc0bd710 100644
--- a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag.qsb
index f7ab8301f3..3303ddec7f 100644
--- a/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/opaquetexture.frag.qsb b/src/quick/scenegraph/shaders_ng/opaquetexture.frag.qsb
index a30e7868c7..785527811a 100644
--- a/src/quick/scenegraph/shaders_ng/opaquetexture.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/opaquetexture.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/opaquetexture.vert.qsb b/src/quick/scenegraph/shaders_ng/opaquetexture.vert.qsb
index 8a62c79ba4..eec3bf66b0 100644
--- a/src/quick/scenegraph/shaders_ng/opaquetexture.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/opaquetexture.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
index bec0a086af..c1e81f4163 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
index 3f9464dd7c..b8d38bdff4 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
index 7f08bcee9e..7e26f3775e 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/shadereffect.frag.qsb b/src/quick/scenegraph/shaders_ng/shadereffect.frag.qsb
index dc3b174553..16046468c2 100644
--- a/src/quick/scenegraph/shaders_ng/shadereffect.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/shadereffect.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/shadereffect.vert.qsb b/src/quick/scenegraph/shaders_ng/shadereffect.vert.qsb
index 06e1e3704a..9365ce95c4 100644
--- a/src/quick/scenegraph/shaders_ng/shadereffect.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/shadereffect.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/smoothcolor.frag.qsb b/src/quick/scenegraph/shaders_ng/smoothcolor.frag.qsb
index 2ad3229e4a..8a30f3eae6 100644
--- a/src/quick/scenegraph/shaders_ng/smoothcolor.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/smoothcolor.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/smoothcolor.vert.qsb b/src/quick/scenegraph/shaders_ng/smoothcolor.vert.qsb
index 7d3a742650..1f187b05ac 100644
--- a/src/quick/scenegraph/shaders_ng/smoothcolor.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/smoothcolor.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/smoothtexture.frag.qsb b/src/quick/scenegraph/shaders_ng/smoothtexture.frag.qsb
index d5b738cc38..780486ca29 100644
--- a/src/quick/scenegraph/shaders_ng/smoothtexture.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/smoothtexture.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/smoothtexture.vert.qsb b/src/quick/scenegraph/shaders_ng/smoothtexture.vert.qsb
index 50be6d62e0..76d03d4ff7 100644
--- a/src/quick/scenegraph/shaders_ng/smoothtexture.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/smoothtexture.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/sprite.frag.qsb b/src/quick/scenegraph/shaders_ng/sprite.frag.qsb
index f6a7913054..2a33d577c7 100644
--- a/src/quick/scenegraph/shaders_ng/sprite.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/sprite.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/sprite.vert.qsb b/src/quick/scenegraph/shaders_ng/sprite.vert.qsb
index c11191feef..c77612a31a 100644
--- a/src/quick/scenegraph/shaders_ng/sprite.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/sprite.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/stencilclip.frag.qsb b/src/quick/scenegraph/shaders_ng/stencilclip.frag.qsb
index 0fcd1d3f80..b0b13a1d5a 100644
--- a/src/quick/scenegraph/shaders_ng/stencilclip.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/stencilclip.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/stencilclip.vert.qsb b/src/quick/scenegraph/shaders_ng/stencilclip.vert.qsb
index 6381f6c8d9..3c091ad73e 100644
--- a/src/quick/scenegraph/shaders_ng/stencilclip.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/stencilclip.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb b/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
index ff7eceba83..b0461a686c 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/styledtext.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb b/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
index 26f791be7f..18e4685d21 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/styledtext.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb b/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
index 5e023b086b..3d9b5a0bdd 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/styledtext_a.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/textmask.frag.qsb b/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
index 4cc598c5f8..cfae9575da 100644
--- a/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/textmask.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/textmask.vert.qsb b/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
index 03be2e457d..2ea425e1c0 100644
--- a/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/textmask.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/texture.frag.qsb b/src/quick/scenegraph/shaders_ng/texture.frag.qsb
index 55e8c23335..47c75b1e78 100644
--- a/src/quick/scenegraph/shaders_ng/texture.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/texture.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/texture.vert.qsb b/src/quick/scenegraph/shaders_ng/texture.vert.qsb
index 7ce3600447..0301a7bfa0 100644
--- a/src/quick/scenegraph/shaders_ng/texture.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/texture.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/vertexcolor.frag.qsb b/src/quick/scenegraph/shaders_ng/vertexcolor.frag.qsb
index 2ad3229e4a..8a30f3eae6 100644
--- a/src/quick/scenegraph/shaders_ng/vertexcolor.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/vertexcolor.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/vertexcolor.vert.qsb b/src/quick/scenegraph/shaders_ng/vertexcolor.vert.qsb
index 1bea18c036..95787f647b 100644
--- a/src/quick/scenegraph/shaders_ng/vertexcolor.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/vertexcolor.vert.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/visualization.frag.qsb b/src/quick/scenegraph/shaders_ng/visualization.frag.qsb
index 6b1a6a6c74..f45b7b4488 100644
--- a/src/quick/scenegraph/shaders_ng/visualization.frag.qsb
+++ b/src/quick/scenegraph/shaders_ng/visualization.frag.qsb
Binary files differ
diff --git a/src/quick/scenegraph/shaders_ng/visualization.vert.qsb b/src/quick/scenegraph/shaders_ng/visualization.vert.qsb
index 5f64c84705..acb29bb0fd 100644
--- a/src/quick/scenegraph/shaders_ng/visualization.vert.qsb
+++ b/src/quick/scenegraph/shaders_ng/visualization.vert.qsb
Binary files differ
diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp
index c081d45268..db82b2d807 100644
--- a/src/quick/util/qquickimageprovider.cpp
+++ b/src/quick/util/qquickimageprovider.cpp
@@ -672,17 +672,17 @@ QSize QQuickImageProviderWithOptions::loadSize(const QSize &originalSize, const
return res;
const bool preserveAspectCropOrFit = options.preserveAspectRatioCrop() || options.preserveAspectRatioFit();
- const bool formatIsSvg = (format == "svg" || format == "svgz");
+ const bool formatIsScalable = (format == "svg" || format == "svgz" || format == "pdf");
- if (!preserveAspectCropOrFit && formatIsSvg && !requestedSize.isEmpty())
+ if (!preserveAspectCropOrFit && formatIsScalable && !requestedSize.isEmpty())
return requestedSize;
qreal ratio = 0.0;
- if (requestedSize.width() && (preserveAspectCropOrFit || formatIsSvg ||
+ if (requestedSize.width() && (preserveAspectCropOrFit || formatIsScalable ||
requestedSize.width() < originalSize.width())) {
ratio = qreal(requestedSize.width()) / originalSize.width();
}
- if (requestedSize.height() && (preserveAspectCropOrFit || formatIsSvg ||
+ if (requestedSize.height() && (preserveAspectCropOrFit || formatIsScalable ||
requestedSize.height() < originalSize.height())) {
qreal hr = qreal(requestedSize.height()) / originalSize.height();
if (ratio == 0.0)
diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp
index c855acc185..375d0265e8 100644
--- a/src/quick/util/qquickpath.cpp
+++ b/src/quick/util/qquickpath.cpp
@@ -301,6 +301,8 @@ void QQuickPath::pathElements_append(QQmlListProperty<QQuickPathElement> *proper
QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement);
if (curve)
d->_pathCurves.append(curve);
+ else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement))
+ d->_pathTexts.append(text);
else {
QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement);
if (attribute && !d->_attributes.contains(attribute->name()))
@@ -329,6 +331,7 @@ void QQuickPath::pathElements_clear(QQmlListProperty<QQuickPathElement> *propert
d->_pathElements.clear();
d->_pathCurves.clear();
d->_pointCache.clear();
+ d->_pathTexts.clear();
}
void QQuickPath::interpolate(int idx, const QString &name, qreal value)
@@ -478,6 +481,8 @@ QPainterPath QQuickPath::createPath(const QPointF &startPoint, const QPointF &en
point.values[percentString] = percent->value();
interpolate(attributePoints, attributePoints.count() - 1, percentString, percent->value());
usesPercent = true;
+ } else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement)) {
+ text->addToPath(path);
}
}
@@ -547,6 +552,9 @@ QPainterPath QQuickPath::createShapePath(const QPointF &startPoint, const QPoint
++index;
}
+ for (QQuickPathText *text : qAsConst(d->_pathTexts))
+ text->addToPath(path);
+
if (closed) {
QPointF end = path.currentPosition();
*closed = startX == end.x() && startY == end.y();
@@ -593,6 +601,8 @@ void QQuickPath::gatherAttributes()
for (QQuickPathElement *pathElement : qAsConst(d->_pathElements)) {
if (QQuickCurve *curve = qobject_cast<QQuickCurve *>(pathElement))
d->_pathCurves.append(curve);
+ else if (QQuickPathText *text = qobject_cast<QQuickPathText *>(pathElement))
+ d->_pathTexts.append(text);
else if (QQuickPathAttribute *attribute = qobject_cast<QQuickPathAttribute *>(pathElement))
attributes.insert(attribute->name());
}
@@ -2619,6 +2629,219 @@ void QQuickPathMultiline::addToPath(QPainterPath &path, const QQuickPathData &)
}
}
+/*!
+ \qmltype PathText
+ \instantiates QQuickPathText
+ \inqmlmodule QtQuick
+ \ingroup qtquick-animation-paths
+ \brief Defines a string in a specified font.
+ \since QtQuick 2.15
+
+ This element defines the shape of a specified string in a specified font. The text's
+ baseline will be translated to the x and y coordinates, and the outlines from the font
+ will be added to the path accordingly.
+
+ \qml
+ PathText {
+ x: 0
+ y: font.pixelSize
+ font.family: "Arial"
+ font.pixelSize: 100
+ text: "Foobar"
+ }
+ \endqml
+
+ \sa Path, QPainterPath::setFillRule, PathPolyline, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg, PathMove
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathText::x
+
+ The horizontal position of the PathText's baseline.
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathText::y
+
+ The vertical position of the PathText's baseline.
+
+ \note This property refers to the position of the baseline of the text, not the top of its bounding box. This may
+ cause some confusion, e.g. when using the PathText with Qt Quick Shapes. See \l FontMetrics for information on how to
+ get the ascent of a font, which can be used to translate the text into the expected position.
+*/
+
+/*!
+ \qmlproperty string QtQuick::PathText::text
+
+ The text for which this PathText should contain the outlines.
+*/
+
+/*!
+ \qmlproperty string QtQuick::PathText::font.family
+
+ Sets the family name of the font.
+
+ The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
+ If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
+ If the family isn't available a family will be set using the font matching algorithm.
+*/
+
+/*!
+ \qmlproperty string QtQuick::PathText::font.styleName
+
+ Sets the style name of the font.
+
+ The style name is case insensitive. If set, the font will be matched against style name instead
+ of the font properties \l font.weight, \l font.bold and \l font.italic.
+*/
+
+/*!
+ \qmlproperty bool QtQuick::PathText::font.bold
+
+ Sets whether the font weight is bold.
+*/
+
+/*!
+ \qmlproperty enumeration QtQuick::PathText::font.weight
+
+ Sets the font's weight.
+
+ The weight can be one of:
+ \list
+ \li Font.Thin
+ \li Font.Light
+ \li Font.ExtraLight
+ \li Font.Normal - the default
+ \li Font.Medium
+ \li Font.DemiBold
+ \li Font.Bold
+ \li Font.ExtraBold
+ \li Font.Black
+ \endlist
+
+ \qml
+ PathText { text: "Hello"; font.weight: Font.DemiBold }
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool QtQuick::PathText::font.italic
+
+ Sets whether the font has an italic style.
+*/
+
+/*!
+ \qmlproperty bool QtQuick::PathText::font.underline
+
+ Sets whether the text is underlined.
+*/
+
+/*!
+ \qmlproperty bool QtQuick::PathText::font.strikeout
+
+ Sets whether the font has a strikeout style.
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathText::font.pointSize
+
+ Sets the font size in points. The point size must be greater than zero.
+*/
+
+/*!
+ \qmlproperty int QtQuick::PathText::font.pixelSize
+
+ Sets the font size in pixels.
+
+ Using this function makes the font device dependent.
+ Use \c pointSize to set the size of the font in a device independent manner.
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathText::font.letterSpacing
+
+ Sets the letter spacing for the font.
+
+ Letter spacing changes the default spacing between individual letters in the font.
+ A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
+*/
+
+/*!
+ \qmlproperty real QtQuick::PathText::font.wordSpacing
+
+ Sets the word spacing for the font.
+
+ Word spacing changes the default spacing between individual words.
+ A positive value increases the word spacing by a corresponding amount of pixels,
+ while a negative value decreases the inter-word spacing accordingly.
+*/
+
+/*!
+ \qmlproperty enumeration QtQuick::PathText::font.capitalization
+
+ Sets the capitalization for the text.
+
+ \list
+ \li Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
+ \li Font.AllUppercase - This alters the text to be rendered in all uppercase type.
+ \li Font.AllLowercase - This alters the text to be rendered in all lowercase type.
+ \li Font.SmallCaps - This alters the text to be rendered in small-caps type.
+ \li Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
+ \endlist
+
+ \qml
+ PathText { text: "Hello"; font.capitalization: Font.AllLowercase }
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool QtQuick::PathText::font.kerning
+
+ Enables or disables the kerning OpenType feature when shaping the text. Disabling this may
+ improve performance when creating or changing the text, at the expense of some cosmetic
+ features. The default value is true.
+
+ \qml
+ PathText { text: "OATS FLAVOUR WAY"; font.kerning: false }
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool QtQuick::PathText::font.preferShaping
+
+ Sometimes, a font will apply complex rules to a set of characters in order to
+ display them correctly. In some writing systems, such as Brahmic scripts, this is
+ required in order for the text to be legible, but in e.g. Latin script, it is merely
+ a cosmetic feature. Setting the \c preferShaping property to false will disable all
+ such features when they are not required, which will improve performance in most cases.
+
+ The default value is true.
+
+ \qml
+ PathText { text: "Some text"; font.preferShaping: false }
+ \endqml
+*/
+
+void QQuickPathText::updatePath() const
+{
+ if (!_path.isEmpty())
+ return;
+
+ _path.addText(_x, _y, _font, _text);
+
+ // Account for distance from baseline to top, since addText() takes baseline position
+ QRectF brect = _path.boundingRect();
+ _path.translate(0.0, -brect.y());
+}
+
+void QQuickPathText::addToPath(QPainterPath &path)
+{
+ if (_text.isEmpty())
+ return;
+ updatePath();
+ path.addPath(_path);
+}
+
QT_END_NAMESPACE
#include "moc_qquickpath_p.cpp"
diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h
index ca0495a90d..159c46d13c 100644
--- a/src/quick/util/qquickpath_p.h
+++ b/src/quick/util/qquickpath_p.h
@@ -63,6 +63,7 @@ QT_REQUIRE_CONFIG(quick_path);
#include <QtCore/QObject>
#include <QtGui/QPainterPath>
+#include <QtGui/QFont>
QT_BEGIN_NAMESPACE
@@ -598,6 +599,106 @@ public:
static QPointF sequentialPointAt(const QPainterPath &path, const qreal &pathLength, const QList<AttributePoint> &attributePoints, QQuickCachedBezier &prevBez, qreal p, qreal *angle = nullptr);
};
+class Q_QUICK_PRIVATE_EXPORT QQuickPathText : public QQuickPathElement
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged)
+ Q_PROPERTY(qreal width READ width NOTIFY changed)
+ Q_PROPERTY(qreal height READ height NOTIFY changed)
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged)
+ QML_NAMED_ELEMENT(PathText)
+ QML_ADDED_IN_MINOR_VERSION(15)
+public:
+ QQuickPathText(QObject *parent=nullptr) : QQuickPathElement(parent)
+ {
+ connect(this, &QQuickPathText::xChanged, this, &QQuickPathElement::changed);
+ connect(this, &QQuickPathText::yChanged, this, &QQuickPathElement::changed);
+ connect(this, &QQuickPathText::textChanged, this, &QQuickPathElement::changed);
+ connect(this, &QQuickPathText::fontChanged, this, &QQuickPathElement::changed);
+
+ connect(this, &QQuickPathElement::changed, this, &QQuickPathText::invalidate);
+ }
+
+ void addToPath(QPainterPath &path);
+
+ qreal x() const { return _x; }
+ qreal y() const { return _y; }
+ QString text() const { return _text; }
+ QFont font() const { return _font; }
+
+ void setX(qreal x)
+ {
+ if (qFuzzyCompare(_x, x))
+ return;
+
+ _x = x;
+ Q_EMIT xChanged();
+ }
+
+ void setY(qreal y)
+ {
+ if (qFuzzyCompare(_y, y))
+ return;
+
+ _y = y;
+ Q_EMIT yChanged();
+ }
+
+ void setText(const QString &text)
+ {
+ if (text == _text)
+ return;
+
+ _text = text;
+ Q_EMIT textChanged();
+ }
+
+ void setFont(const QFont &font)
+ {
+ if (font == _font)
+ return;
+
+ _font = font;
+ Q_EMIT fontChanged();
+ }
+
+ qreal width() const
+ {
+ updatePath();
+ return _path.boundingRect().width();
+ }
+
+ qreal height() const
+ {
+ updatePath();
+ return _path.boundingRect().height();
+ }
+
+Q_SIGNALS:
+ void xChanged();
+ void yChanged();
+ void textChanged();
+ void fontChanged();
+
+private Q_SLOTS:
+ void invalidate()
+ {
+ _path.clear();
+ }
+
+private:
+ void updatePath() const;
+
+ QString _text;
+ qreal _x = qreal(0.0);
+ qreal _y = qreal(0.0);
+ QFont _font;
+
+ mutable QPainterPath _path;
+};
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickPathElement)
@@ -614,5 +715,6 @@ QML_DECLARE_TYPE(QQuickPathSvg)
QML_DECLARE_TYPE(QQuickPathPercent)
QML_DECLARE_TYPE(QQuickPathPolyline)
QML_DECLARE_TYPE(QQuickPath)
+QML_DECLARE_TYPE(QQuickPathText)
#endif // QQUICKPATH_H
diff --git a/src/quick/util/qquickpath_p_p.h b/src/quick/util/qquickpath_p_p.h
index e26001ec77..5505b876c1 100644
--- a/src/quick/util/qquickpath_p_p.h
+++ b/src/quick/util/qquickpath_p_p.h
@@ -80,6 +80,7 @@ public:
QList<QQuickPath::AttributePoint> _attributePoints;
QStringList _attributes;
QList<QQuickCurve*> _pathCurves;
+ QList<QQuickPathText*> _pathTexts;
mutable QQuickCachedBezier prevBez;
QQmlNullableValue<qreal> startX;
QQmlNullableValue<qreal> startY;
diff --git a/src/quickshapes/qquickshapegenericrenderer_p.h b/src/quickshapes/qquickshapegenericrenderer_p.h
index 4590c662c1..75c4277383 100644
--- a/src/quickshapes/qquickshapegenericrenderer_p.h
+++ b/src/quickshapes/qquickshapegenericrenderer_p.h
@@ -57,6 +57,7 @@
#include <qsggeometry.h>
#include <qsgmaterial.h>
#include <qsgrendererinterface.h>
+#include <qsgtexture.h>
#include <QtCore/qrunnable.h>
QT_BEGIN_NAMESPACE
diff --git a/src/quickshapes/shaders_ng/conicalgradient.frag.qsb b/src/quickshapes/shaders_ng/conicalgradient.frag.qsb
index cee844fab4..f82d798d87 100644
--- a/src/quickshapes/shaders_ng/conicalgradient.frag.qsb
+++ b/src/quickshapes/shaders_ng/conicalgradient.frag.qsb
Binary files differ
diff --git a/src/quickshapes/shaders_ng/conicalgradient.vert.qsb b/src/quickshapes/shaders_ng/conicalgradient.vert.qsb
index 50508e242a..7d306e973b 100644
--- a/src/quickshapes/shaders_ng/conicalgradient.vert.qsb
+++ b/src/quickshapes/shaders_ng/conicalgradient.vert.qsb
Binary files differ
diff --git a/src/quickshapes/shaders_ng/lineargradient.frag.qsb b/src/quickshapes/shaders_ng/lineargradient.frag.qsb
index d25d5e7a79..640c3c334f 100644
--- a/src/quickshapes/shaders_ng/lineargradient.frag.qsb
+++ b/src/quickshapes/shaders_ng/lineargradient.frag.qsb
Binary files differ
diff --git a/src/quickshapes/shaders_ng/lineargradient.vert.qsb b/src/quickshapes/shaders_ng/lineargradient.vert.qsb
index c48646b036..1b5b19ded8 100644
--- a/src/quickshapes/shaders_ng/lineargradient.vert.qsb
+++ b/src/quickshapes/shaders_ng/lineargradient.vert.qsb
Binary files differ
diff --git a/src/quickshapes/shaders_ng/radialgradient.frag.qsb b/src/quickshapes/shaders_ng/radialgradient.frag.qsb
index 207e4d3429..1bcb8d55ef 100644
--- a/src/quickshapes/shaders_ng/radialgradient.frag.qsb
+++ b/src/quickshapes/shaders_ng/radialgradient.frag.qsb
Binary files differ
diff --git a/src/quickshapes/shaders_ng/radialgradient.vert.qsb b/src/quickshapes/shaders_ng/radialgradient.vert.qsb
index dadbfd60d6..7a77792e08 100644
--- a/src/quickshapes/shaders_ng/radialgradient.vert.qsb
+++ b/src/quickshapes/shaders_ng/radialgradient.vert.qsb
Binary files differ
diff --git a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
index d2cfd3897a..1c1f785560 100644
--- a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
+++ b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp
@@ -88,8 +88,7 @@ public:
QList<LogEntry> logBuffer;
protected:
- //inherited from QQmlDebugClient
- void messageReceived(const QByteArray &data);
+ void messageReceived(const QByteArray &data) override;
signals:
void debugOutput();
diff --git a/tests/auto/qml/ecmascripttests/BLACKLIST b/tests/auto/qml/ecmascripttests/BLACKLIST
new file mode 100644
index 0000000000..1ed255e9e2
--- /dev/null
+++ b/tests/auto/qml/ecmascripttests/BLACKLIST
@@ -0,0 +1,4 @@
+[runInterpreted]
+macos ci
+[runJitted]
+macos
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 28efb519ee..7b59087a72 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -264,6 +264,8 @@ private slots:
void printCircularArray();
void typedArraySet();
+ void uiLanguage();
+
public:
Q_INVOKABLE QJSValue throwingCppMethod1();
Q_INVOKABLE void throwingCppMethod2();
@@ -5143,6 +5145,33 @@ void tst_QJSEngine::typedArraySet()
}
}
+void tst_QJSEngine::uiLanguage()
+{
+ {
+ QJSEngine engine;
+
+ QVERIFY(!engine.globalObject().hasProperty("Qt"));
+
+ engine.installExtensions(QJSEngine::TranslationExtension);
+ QVERIFY(engine.globalObject().hasProperty("Qt"));
+ QVERIFY(engine.globalObject().property("Qt").hasProperty("uiLanguage"));
+
+ engine.setUiLanguage("Blah");
+ QCOMPARE(engine.globalObject().property("Qt").property("uiLanguage").toString(), "Blah");
+
+ engine.evaluate("Qt.uiLanguage = \"another\"");
+ QCOMPARE(engine.globalObject().property("Qt").property("uiLanguage").toString(), "another");
+ }
+
+ {
+ QQmlEngine qmlEngine;
+ QVERIFY(qmlEngine.globalObject().hasProperty("Qt"));
+ QVERIFY(qmlEngine.globalObject().property("Qt").hasProperty("uiLanguage"));
+ qmlEngine.setUiLanguage("Blah");
+ QCOMPARE(qmlEngine.globalObject().property("Qt").property("uiLanguage").toString(), "Blah");
+ }
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"
diff --git a/tests/auto/qml/qqmlapplicationengine/data/i18n/qml_de_CH.qm b/tests/auto/qml/qqmlapplicationengine/data/i18n/qml_de_CH.qm
new file mode 100644
index 0000000000..926d74f905
--- /dev/null
+++ b/tests/auto/qml/qqmlapplicationengine/data/i18n/qml_de_CH.qm
Binary files differ
diff --git a/tests/auto/qml/qqmlapplicationengine/data/i18n/qml_de_CH.ts b/tests/auto/qml/qqmlapplicationengine/data/i18n/qml_de_CH.ts
new file mode 100644
index 0000000000..2105cfb2cf
--- /dev/null
+++ b/tests/auto/qml/qqmlapplicationengine/data/i18n/qml_de_CH.ts
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_CH" sourcelanguage="en">
+<context>
+ <name>loadTranslation</name>
+ <message>
+ <source>translate it</source>
+ <translation>Grüezi</translation>
+ </message>
+</context>
+</TS>
diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
index 5e855efe1a..b019ff4535 100644
--- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
+++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp
@@ -53,6 +53,7 @@ private slots:
void removeObjectsWhenDestroyed();
void loadTranslation_data();
void loadTranslation();
+ void translationChange();
void setInitialProperties();
void failureToLoadTriggersWarningSignal();
@@ -278,6 +279,28 @@ void tst_qqmlapplicationengine::loadTranslation()
QCOMPARE(rootObject->property("translation").toString(), translation);
}
+void tst_qqmlapplicationengine::translationChange()
+{
+ if (QLocale().language() == QLocale::SwissGerman) {
+ QSKIP("Skipping this when running under the Swiss locale as we would always load translation.");
+ }
+
+ QQmlApplicationEngine engine(testFileUrl("loadTranslation.qml"));
+
+ QCOMPARE(engine.uiLanguage(), QLocale().bcp47Name());
+
+ QObject *rootObject = engine.rootObjects().first();
+ QVERIFY(rootObject);
+
+ QCOMPARE(rootObject->property("translation").toString(), "translated");
+
+ engine.setUiLanguage("de_CH");
+ QCOMPARE(rootObject->property("translation").toString(), QString::fromUtf8("Gr\u00FCezi"));
+
+ engine.setUiLanguage(QString());
+ QCOMPARE(rootObject->property("translation").toString(), "translate it");
+}
+
void tst_qqmlapplicationengine::setInitialProperties()
{
QQmlApplicationEngine test {};
diff --git a/tests/auto/qml/qqmlengine/data/uiLanguage.qml b/tests/auto/qml/qqmlengine/data/uiLanguage.qml
new file mode 100644
index 0000000000..bc20351245
--- /dev/null
+++ b/tests/auto/qml/qqmlengine/data/uiLanguage.qml
@@ -0,0 +1,9 @@
+import QtQml 2.15
+QtObject {
+ property string chosenLanguage: Qt.uiLanguage
+ property string textToTranslate: {
+ numberOfTranslationBindingEvaluations++;
+ return qsTr("Translate me maybe");
+ }
+ property int numberOfTranslationBindingEvaluations: 0
+}
diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
index d782df3e7f..ab4c083b65 100644
--- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
+++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp
@@ -84,6 +84,7 @@ private slots:
void aggressiveGc();
void cachedGetterLookup_qtbug_75335();
void createComponentOnSingletonDestruction();
+ void uiLanguage();
public slots:
QObject *createAQObjectForOwnershipTest ()
@@ -1175,6 +1176,38 @@ void tst_qqmlengine::createComponentOnSingletonDestruction()
QVERIFY(obj);
}
+void tst_qqmlengine::uiLanguage()
+{
+ QQmlEngine engine;
+
+ QObject::connect(&engine, &QJSEngine::uiLanguageChanged, [&engine]() {
+ engine.retranslate();
+ });
+
+ QSignalSpy uiLanguageChangeSpy(&engine, SIGNAL(uiLanguageChanged()));
+
+ QQmlComponent component(&engine, testFileUrl("uiLanguage.qml"));
+
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, (component.url().toString() + ":2:1: QML QtObject: Binding loop detected for property \"textToTranslate\"").toLatin1());
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(!object.isNull());
+
+ QVERIFY(engine.uiLanguage().isEmpty());
+ QCOMPARE(object->property("numberOfTranslationBindingEvaluations").toInt(), 1);
+
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, (component.url().toString() + ":2:1: QML QtObject: Binding loop detected for property \"textToTranslate\"").toLatin1());
+ engine.setUiLanguage("TestLanguage");
+ QCOMPARE(object->property("numberOfTranslationBindingEvaluations").toInt(), 2);
+ QCOMPARE(object->property("chosenLanguage").toString(), "TestLanguage");
+
+
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, (component.url().toString() + ":2:1: QML QtObject: Binding loop detected for property \"textToTranslate\"").toLatin1());
+ engine.evaluate("Qt.uiLanguage = \"anotherLanguage\"");
+ QCOMPARE(engine.uiLanguage(), QString("anotherLanguage"));
+ QCOMPARE(object->property("numberOfTranslationBindingEvaluations").toInt(), 3);
+ QCOMPARE(object->property("chosenLanguage").toString(), "anotherLanguage");
+}
+
QTEST_MAIN(tst_qqmlengine)
#include "tst_qqmlengine.moc"
diff --git a/tests/auto/qml/qqmllanguage/data/InlineComponentBase.qml b/tests/auto/qml/qqmllanguage/data/InlineComponentBase.qml
new file mode 100644
index 0000000000..0b297a7779
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/InlineComponentBase.qml
@@ -0,0 +1,9 @@
+import QtQml 2.15
+
+QtObject {
+ property alias i: icInstance.i
+ component IC : QtObject {
+ property int i: 42
+ }
+ property QtObject ic: IC {id: icInstance}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/InlineComponentChild.qml b/tests/auto/qml/qqmllanguage/data/InlineComponentChild.qml
new file mode 100644
index 0000000000..49a90ab7da
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/InlineComponentChild.qml
@@ -0,0 +1,7 @@
+import QtQml 2.15
+
+InlineComponentBase {
+ component IC : QtObject {
+ property int i: 13
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/InlineComponentProvider.qml b/tests/auto/qml/qqmllanguage/data/InlineComponentProvider.qml
new file mode 100644
index 0000000000..6058e32b2f
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/InlineComponentProvider.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.15
+
+Item {
+ component StyledRectangle: Rectangle {
+ width: 24
+ height: 24
+ color: "red"
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/InlineComponentProvider2.qml b/tests/auto/qml/qqmllanguage/data/InlineComponentProvider2.qml
new file mode 100644
index 0000000000..b5a0efaccf
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/InlineComponentProvider2.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.15
+
+Item {
+ property color myColor: "red"
+ component StyledRectangle: Rectangle {
+ width: 24
+ height: 24
+ color: myColor
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/InlineComponentProvider3.qml b/tests/auto/qml/qqmllanguage/data/InlineComponentProvider3.qml
new file mode 100644
index 0000000000..9a4f1fd272
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/InlineComponentProvider3.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.15
+
+Item {
+ Item {
+ component StyledRectangle: Rectangle {
+ width: 24
+ height: 24
+ color: "red"
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/InlineComponentProviderChild.qml b/tests/auto/qml/qqmllanguage/data/InlineComponentProviderChild.qml
new file mode 100644
index 0000000000..ddb55e55e6
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/InlineComponentProviderChild.qml
@@ -0,0 +1 @@
+InlineComponentProvider {}
diff --git a/tests/auto/qml/qqmllanguage/data/InlineComponentReexporter.qml b/tests/auto/qml/qqmllanguage/data/InlineComponentReexporter.qml
new file mode 100644
index 0000000000..24bf6f771e
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/InlineComponentReexporter.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.14
+
+QtObject {
+ component StyledRectangle: InlineComponentProvider.StyledRectangle {
+ color: "green"
+ }
+
+}
diff --git a/tests/auto/qml/qqmllanguage/data/icCycleViaProperty.qml b/tests/auto/qml/qqmllanguage/data/icCycleViaProperty.qml
new file mode 100644
index 0000000000..c5aa4cfdf5
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/icCycleViaProperty.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.15
+
+Item {
+ component A : Item {
+ property var test: B {}
+ }
+ component B: A {}
+ A {}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/icSimpleCycle.qml b/tests/auto/qml/qqmllanguage/data/icSimpleCycle.qml
new file mode 100644
index 0000000000..69e74f7c96
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/icSimpleCycle.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.15
+
+Item {
+ component A : B {}
+ component B: A {}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/inlineComponentOrder.qml b/tests/auto/qml/qqmllanguage/data/inlineComponentOrder.qml
new file mode 100644
index 0000000000..a96f68e56a
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/inlineComponentOrder.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.15
+
+Item {
+ width: 600
+ height: 480
+ IC2 {
+ objectName: "icInstance"
+ anchors.centerIn: parent
+ }
+
+ component IC2: IC1 {}
+ component IC0: Rectangle {
+ height: 200
+ width: 200
+ color: "blue"
+ }
+ component IC1: IC0 {}
+
+
+}
diff --git a/tests/auto/qml/qqmllanguage/data/inlineComponentUser1.qml b/tests/auto/qml/qqmllanguage/data/inlineComponentUser1.qml
new file mode 100644
index 0000000000..8968a20112
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/inlineComponentUser1.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.14
+
+Item {
+ width: 600
+ height: 480
+ property InlineComponentProvider.StyledRectangle myProp: InlineComponentProvider.StyledRectangle {}
+ InlineComponentProvider.StyledRectangle {
+ objectName: "icInstance"
+ anchors.centerIn: parent
+ color: "blue"
+ }
+
+}
diff --git a/tests/auto/qml/qqmllanguage/data/inlineComponentUser2.qml b/tests/auto/qml/qqmllanguage/data/inlineComponentUser2.qml
new file mode 100644
index 0000000000..dc6e3850db
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/inlineComponentUser2.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.14
+
+Item {
+ width: 600
+ height: 480
+ property InlineComponentProvider.StyledRectangle myProp: InlineComponentReexporter.StyledRectangle {
+ objectName: "icInstance"
+ }
+
+}
diff --git a/tests/auto/qml/qqmllanguage/data/inlineComponentUser3.qml b/tests/auto/qml/qqmllanguage/data/inlineComponentUser3.qml
new file mode 100644
index 0000000000..c57c4cad01
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/inlineComponentUser3.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.14
+
+Item {
+ width: 600
+ height: 480
+ component StyledRectangle: Rectangle {
+ width: 24
+ height: 24
+ color: "blue"
+ }
+ StyledRectangle {
+ objectName: "icInstance"
+ anchors.centerIn: parent
+ }
+
+}
diff --git a/tests/auto/qml/qqmllanguage/data/inlineComponentUser4.qml b/tests/auto/qml/qqmllanguage/data/inlineComponentUser4.qml
new file mode 100644
index 0000000000..9f3903c8df
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/inlineComponentUser4.qml
@@ -0,0 +1,12 @@
+import QtQuick 2.14
+
+Item {
+ width: 600
+ height: 480
+ property color myColor: "blue"
+ InlineComponentProvider2.StyledRectangle {
+ objectName: "icInstance"
+ anchors.centerIn: parent
+ }
+
+}
diff --git a/tests/auto/qml/qqmllanguage/data/inlineComponentUser5.qml b/tests/auto/qml/qqmllanguage/data/inlineComponentUser5.qml
new file mode 100644
index 0000000000..150d0c2ded
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/inlineComponentUser5.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.15
+
+Item {
+ width: 600
+ height: 480
+ property var test: InlineComponentProvider3.StyledRectangle {
+ objectName: "icInstance"
+ anchors.centerIn: parent
+ }
+
+}
diff --git a/tests/auto/qml/qqmllanguage/data/invalidRoot.4.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidRoot.4.errors.txt
index 3b90f573a2..41cb0eaac1 100644
--- a/tests/auto/qml/qqmllanguage/data/invalidRoot.4.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/invalidRoot.4.errors.txt
@@ -1 +1 @@
-3:1:Bar.Item - Bar is not a namespace
+3:1:Bar.Item - Bar is neither a type nor a namespace
diff --git a/tests/auto/qml/qqmllanguage/data/invalidTypeName.4.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidTypeName.4.errors.txt
index 3b90f573a2..41cb0eaac1 100644
--- a/tests/auto/qml/qqmllanguage/data/invalidTypeName.4.errors.txt
+++ b/tests/auto/qml/qqmllanguage/data/invalidTypeName.4.errors.txt
@@ -1 +1 @@
-3:1:Bar.Item - Bar is not a namespace
+3:1:Bar.Item - Bar is neither a type nor a namespace
diff --git a/tests/auto/qml/qqmllanguage/data/nestedIC.qml b/tests/auto/qml/qqmllanguage/data/nestedIC.qml
new file mode 100644
index 0000000000..04cef64d54
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nestedIC.qml
@@ -0,0 +1,7 @@
+import QtQuick 2.15
+
+Item {
+ component Outer : Item {
+ component Inner : Item {}
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/nonExistingICUser1.qml b/tests/auto/qml/qqmllanguage/data/nonExistingICUser1.qml
new file mode 100644
index 0000000000..a07a6a9838
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nonExistingICUser1.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.15
+
+Item {
+ property InlineComponentProvider.NonExisting myProp
+}
diff --git a/tests/auto/qml/qqmllanguage/data/nonExistingICUser2.qml b/tests/auto/qml/qqmllanguage/data/nonExistingICUser2.qml
new file mode 100644
index 0000000000..5c24962def
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nonExistingICUser2.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.15
+
+Item {
+ InlineComponentProvider.NotExisting {}
+}
diff --git a/tests/auto/qml/qqmllanguage/data/nonExistingICUser3.qml b/tests/auto/qml/qqmllanguage/data/nonExistingICUser3.qml
new file mode 100644
index 0000000000..34595707fc
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nonExistingICUser3.qml
@@ -0,0 +1,3 @@
+import QtQuick 2.15
+
+InlineComponentProvider.NotExisting {}
diff --git a/tests/auto/qml/qqmllanguage/data/nonExistingICUser4.qml b/tests/auto/qml/qqmllanguage/data/nonExistingICUser4.qml
new file mode 100644
index 0000000000..2be01ccd96
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nonExistingICUser4.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import "singleton" as MySingleton
+
+Item {
+ property MySingleton.SingletonTypeWithIC.NonExisting singletonIC
+}
diff --git a/tests/auto/qml/qqmllanguage/data/nonExistingICUser5.qml b/tests/auto/qml/qqmllanguage/data/nonExistingICUser5.qml
new file mode 100644
index 0000000000..a2ca5db6de
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/nonExistingICUser5.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.15
+
+Item {
+ property InlineComponentProviderChild.StyledRectangle myProp
+}
diff --git a/tests/auto/qml/qqmllanguage/data/singleton/SingletonTypeWithIC.qml b/tests/auto/qml/qqmllanguage/data/singleton/SingletonTypeWithIC.qml
new file mode 100644
index 0000000000..bd724c4aeb
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/singleton/SingletonTypeWithIC.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.0
+pragma Singleton
+
+Item {
+ id: singletonId
+ component IC1: Item {
+ property int iProp: 42
+ property string sProp: "Hello, world"
+ property Rectangle myRect: Rectangle {color: "green"}
+ }
+ component IC2: Item {
+ property int iProp: 13
+ property string sProp: "Goodbye, world"
+ property Rectangle myRect: Rectangle {color: "red"}
+ }
+}
diff --git a/tests/auto/qml/qqmllanguage/data/singleton/qmldir b/tests/auto/qml/qqmllanguage/data/singleton/qmldir
index 533fb6999a..727b09b4e8 100644
--- a/tests/auto/qml/qqmllanguage/data/singleton/qmldir
+++ b/tests/auto/qml/qqmllanguage/data/singleton/qmldir
@@ -1,3 +1,4 @@
singleton SingletonType SingletonType.qml
+singleton SingletonTypeWithIC SingletonTypeWithIC.qml
diff --git a/tests/auto/qml/qqmllanguage/data/singletonICTest.qml b/tests/auto/qml/qqmllanguage/data/singletonICTest.qml
new file mode 100644
index 0000000000..d0d3b079be
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/singletonICTest.qml
@@ -0,0 +1,6 @@
+import QtQuick 2.0
+import "singleton" as MySingleton
+
+Item {
+ property MySingleton.SingletonTypeWithIC.IC1 singleton1: MySingleton.SingletonTypeWithIC.IC1 {};
+}
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index 089daf3ed5..4d2f773dbf 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -306,6 +306,16 @@ private slots:
void extendedForeignTypes();
+ void inlineComponent();
+ void inlineComponent_data();
+ void inlineComponentReferenceCycle_data();
+ void inlineComponentReferenceCycle();
+ void nestedInlineComponentNotAllowed();
+ void inlineComponentStaticTypeResolution();
+ void inlineComponentInSingleton();
+ void nonExistingInlineComponent_data();
+ void nonExistingInlineComponent();
+
void selfReference();
void selfReferencingSingleton();
@@ -2780,12 +2790,12 @@ void tst_qqmllanguage::importsLocal_data()
QTest::newRow("local import QTBUG-7721 A")
<< "subdir.Test {}" // no longer allowed (QTBUG-7721)
<< ""
- << "subdir.Test - subdir is not a namespace";
+ << "subdir.Test - subdir is neither a type nor a namespace";
QTest::newRow("local import QTBUG-7721 B")
<< "import \"subdir\" as X\n"
"X.subsubdir.SubTest {}" // no longer allowed (QTBUG-7721)
<< ""
- << "X.subsubdir.SubTest - nested namespaces not allowed";
+ << "X.subsubdir.SubTest - subsubdir is not a type";
QTest::newRow("local import as")
<< "import \"subdir\" as T\n"
"T.Test {}"
@@ -5408,6 +5418,128 @@ void tst_qqmllanguage::overrideSingleton()
check("uncreatable", "UncreatableSingleton");
}
+void tst_qqmllanguage::inlineComponent()
+{
+ QFETCH(QUrl, componentUrl);
+ QFETCH(QColor, color);
+ QFETCH(int, width);
+ QQmlEngine engine;
+ QQmlComponent component(&engine, componentUrl);
+ QScopedPointer<QObject> o(component.create());
+ if (component.isError()) {
+ qDebug() << component.errorString();
+ }
+ QVERIFY(!o.isNull());
+ auto icInstance = o->findChild<QObject *>("icInstance");
+ QVERIFY(icInstance);
+ QCOMPARE(icInstance->property("color").value<QColor>(),color);
+ QCOMPARE(icInstance->property("width").value<qreal>(), width);
+}
+
+void tst_qqmllanguage::inlineComponent_data()
+{
+ QTest::addColumn<QUrl>("componentUrl");
+ QTest::addColumn<QColor>("color");
+ QTest::addColumn<int>("width");
+
+ QTest::newRow("Usage from other component") << testFileUrl("inlineComponentUser1.qml") << QColorConstants::Blue << 24;
+ QTest::newRow("Reexport") << testFileUrl("inlineComponentUser2.qml") << QColorConstants::Svg::green << 24;
+ QTest::newRow("Usage in same component") << testFileUrl("inlineComponentUser3.qml") << QColorConstants::Blue << 24;
+
+ QTest::newRow("Resolution happens at instantiation") << testFileUrl("inlineComponentUser4.qml") << QColorConstants::Blue << 24;
+ QTest::newRow("Non-toplevel IC is found") << testFileUrl("inlineComponentUser5.qml") << QColorConstants::Svg::red << 24;
+
+ QTest::newRow("Resolved in correct order") << testFileUrl("inlineComponentOrder.qml") << QColorConstants::Blue << 200;
+}
+
+void tst_qqmllanguage::inlineComponentReferenceCycle_data()
+{
+ QTest::addColumn<QUrl>("componentUrl");
+
+ QTest::newRow("Simple cycle") << testFileUrl("icSimpleCycle.qml");
+ QTest::newRow("Via property") << testFileUrl("icCycleViaProperty.qml");
+}
+
+void tst_qqmllanguage::inlineComponentReferenceCycle()
+{
+ QFETCH(QUrl, componentUrl);
+ QQmlEngine engine;
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "QQmlComponent: Component is not ready");
+ QQmlComponent component(&engine, componentUrl);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o.isNull());
+ QVERIFY(component.isError());
+ QCOMPARE(component.errorString(), componentUrl.toString() + QLatin1String(":-1 Inline components form a cycle!\n"));
+}
+
+void tst_qqmllanguage::nestedInlineComponentNotAllowed()
+{
+ QQmlEngine engine;
+ auto url = testFileUrl("nestedIC.qml");
+ QQmlComponent component(&engine, url);
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "QQmlComponent: Component is not ready");
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(component.isError());
+ QCOMPARE(component.errorString(), QLatin1String("%1:%2").arg(url.toString(), QLatin1String("5 Nested inline components are not supported\n")));
+}
+
+void tst_qqmllanguage::inlineComponentStaticTypeResolution()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("InlineComponentChild.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(o);
+ QCOMPARE(o->property("i").toInt(), 42);
+}
+
+void tst_qqmllanguage::inlineComponentInSingleton()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("singletonICTest.qml"));
+ VERIFY_ERRORS(0);
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+ auto untyped = o->property("singleton1");
+ QVERIFY(untyped.isValid());
+ auto singleton1 = untyped.value<QObject*>();
+ QVERIFY(singleton1);
+ QCOMPARE(singleton1->property("iProp").value<int>(), 42);
+ QCOMPARE(singleton1->property("sProp").value<QString>(), QString::fromLatin1("Hello, world"));
+ QVERIFY(!o.isNull());
+}
+
+void tst_qqmllanguage::nonExistingInlineComponent_data()
+{
+ QTest::addColumn<QUrl>("componentUrl");
+ QTest::addColumn<QString>("errorMessage");
+ QTest::addColumn<int>("line");
+ QTest::addColumn<int>("column");
+
+ QTest::newRow("Property type") << testFileUrl("nonExistingICUser1.qml") << QString("Type InlineComponentProvider has no inline component type called NonExisting") << 4 << 5;
+ QTest::newRow("Instantiation") << testFileUrl("nonExistingICUser2.qml") << QString("Type InlineComponentProvider has no inline component type called NotExisting") << 4 << 5;
+ QTest::newRow("Inheritance") << testFileUrl("nonExistingICUser3.qml") << QString("Type InlineComponentProvider has no inline component type called NotExisting") << 3 << 1;
+ QTest::newRow("From singleton") << testFileUrl("nonExistingICUser4.qml") << QString("Type MySingleton.SingletonTypeWithIC has no inline component type called NonExisting") << 5 << 5;
+
+ QTest::newRow("Cannot access parent inline components from child") << testFileUrl("nonExistingICUser5.qml") << QString("Type InlineComponentProviderChild has no inline component type called StyledRectangle") << 4 << 5;
+}
+
+void tst_qqmllanguage::nonExistingInlineComponent()
+{
+ QFETCH(QUrl, componentUrl);
+ QFETCH(QString, errorMessage);
+ QFETCH(int, line);
+ QFETCH(int, column);
+ QQmlEngine engine;
+ QQmlComponent component(&engine, componentUrl);
+ auto errors = component.errors();
+ QCOMPARE(errors.size(), 1);
+ const auto &error = errors.first();
+ QCOMPARE(error.description(), errorMessage);
+ QCOMPARE(error.line(), line);
+ QCOMPARE(error.column(), column);
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qml/qqmllistmodel/qqmllistmodel.pro b/tests/auto/qml/qqmllistmodel/qqmllistmodel.pro
index 4d44d6b22b..c0808f8599 100644
--- a/tests/auto/qml/qqmllistmodel/qqmllistmodel.pro
+++ b/tests/auto/qml/qqmllistmodel/qqmllistmodel.pro
@@ -8,4 +8,4 @@ include (../../shared/util.pri)
TESTDATA = data/*
-QT += core-private gui-private qml-private quick-private testlib qmlmodels-private
+QT += core-private gui-private qml-private quick-private testlib qmlmodels-private
diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
index 75a932b6f4..d54e3467b7 100644
--- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
+++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp
@@ -700,7 +700,7 @@ void tst_qqmllistmodel::error_data()
QTest::newRow("unknown qualified ListElement not allowed")
<< "import QtQuick 2.0\nListModel { Foo.ListElement { a: 123 } }"
- << "Foo.ListElement - Foo is not a namespace";
+ << "Foo.ListElement - Foo is neither a type nor a namespace";
}
void tst_qqmllistmodel::error()
diff --git a/tests/auto/qmltest/animatedimage/BLACKLIST b/tests/auto/qmltest/animatedimage/BLACKLIST
index 3a5ed393ea..25eb7a7cff 100644
--- a/tests/auto/qmltest/animatedimage/BLACKLIST
+++ b/tests/auto/qmltest/animatedimage/BLACKLIST
@@ -1,2 +1,2 @@
[AnimatedImage::test_crashRaceCondition_replyFinished]
-osx-10.13
+macos
diff --git a/tests/auto/qmltest/listview/data/MultiDelegate3.qml b/tests/auto/qmltest/listview/data/MultiDelegate3.qml
new file mode 100644
index 0000000000..75116e0f9b
--- /dev/null
+++ b/tests/auto/qmltest/listview/data/MultiDelegate3.qml
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, 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 The Qt Company Ltd 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$
+**
+****************************************************************************/
+
+import QtQuick 2.12
+import QtQml.Models 2.12
+import Qt.labs.qmlmodels 1.0
+
+ListView {
+ width: 400
+ height: 400
+
+ property var item1: QtObject {
+ property string dataType: "rect"
+ property color color: "red"
+ }
+ property var item2: QtObject {
+ property string dataType: "text"
+ property string text: "Hello world"
+ }
+ model: [ item1, item2 ]
+
+ delegate: DelegateChooser {
+ role: "dataType"
+ DelegateChoice {
+ roleValue: "rect"
+ delegate: Rectangle {
+ width: parent.width
+ height: 50
+ color: modelData.color
+ }
+ }
+ DelegateChoice {
+ roleValue: "text"
+ delegate: Text {
+ width: parent.width
+ height: 50
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: modelData.text
+ }
+ }
+
+ DelegateChoice {
+ delegate: Item {
+ width: parent.width
+ height: 50
+ }
+ }
+ }
+}
diff --git a/tests/auto/qmltest/listview/tst_listview.qml b/tests/auto/qmltest/listview/tst_listview.qml
index 5e9bb22e8e..bea6b45c3a 100644
--- a/tests/auto/qmltest/listview/tst_listview.qml
+++ b/tests/auto/qmltest/listview/tst_listview.qml
@@ -213,6 +213,10 @@ Item {
id: multiDelegate2
}
+ MultiDelegate3 {
+ id: multiDelegate3
+ }
+
TestCase {
name: "ListView"
when: windowShown
@@ -414,5 +418,18 @@ Item {
var delegate = multiDelegate2.itemAt(10, row.y)
compare(delegate.choiceType, row.type)
}
+
+ function test_multipleDelegates3_data() {
+ return [
+ { y: 25, type: "Rectangle", property: "color", value: "#ff0000" },
+ { y: 75, type: "Text", property: "text", value: "Hello world" }
+ ]
+ }
+
+ function test_multipleDelegates3(row) {
+ var delegate = multiDelegate3.itemAt(10, row.y)
+ verify(delegate.toString().includes(row.type))
+ compare(delegate[row.property], row.value)
+ }
}
}
diff --git a/tests/auto/qmltest/textedit/BLACKLIST b/tests/auto/qmltest/textedit/BLACKLIST
index e06cba3e8f..ac1ca6d8cf 100644
--- a/tests/auto/qmltest/textedit/BLACKLIST
+++ b/tests/auto/qmltest/textedit/BLACKLIST
@@ -1,6 +1,6 @@
# Blacklist for testing
[TextEdit::test_textentry]
-osx-10.12
+macos
[TextEdit::test_textentry_char]
-osx-10.12
+macos
diff --git a/tests/auto/quick/qquickcanvasitem/BLACKLIST b/tests/auto/quick/qquickcanvasitem/BLACKLIST
new file mode 100644
index 0000000000..21580b6730
--- /dev/null
+++ b/tests/auto/quick/qquickcanvasitem/BLACKLIST
@@ -0,0 +1,14 @@
+[arcTo::test_transform]
+macos
+[canvas::test_paint]
+macos
+[canvas::test_save]
+macos
+[canvas::test_implicitlySizedParent]
+macos ci
+[canvas::test_toDataURL]
+macos
+[fillRect::test_fillRect]
+macos
+[imagedata::test_rounding]
+macos ci
diff --git a/tests/auto/quick/qquickitem2/data/mapCoordinates.qml b/tests/auto/quick/qquickitem2/data/mapCoordinates.qml
index 596dedab90..3e34633338 100644
--- a/tests/auto/quick/qquickitem2/data/mapCoordinates.qml
+++ b/tests/auto/quick/qquickitem2/data/mapCoordinates.qml
@@ -49,11 +49,21 @@ Item {
return Qt.point(pos.x, pos.y)
}
+ function mapAToBPoint(x, y) {
+ var pos = itemA.mapToItem(itemB, Qt.point(x, y))
+ return Qt.point(pos.x, pos.y)
+ }
+
function mapAFromB(x, y) {
var pos = itemA.mapFromItem(itemB, x, y)
return Qt.point(pos.x, pos.y)
}
+ function mapAFromBPoint(x, y) {
+ var pos = itemA.mapFromItem(itemB, Qt.point(x, y))
+ return Qt.point(pos.x, pos.y)
+ }
+
function mapAToNull(x, y) {
var pos = itemA.mapToItem(null, x, y)
return Qt.point(pos.x, pos.y)
@@ -69,11 +79,21 @@ Item {
return Qt.point(pos.x, pos.y)
}
+ function mapAToGlobalPoint(x, y) {
+ var pos = itemA.mapToGlobal(Qt.point(x, y))
+ return Qt.point(pos.x, pos.y)
+ }
+
function mapAFromGlobal(x, y) {
var pos = itemA.mapFromGlobal(x, y)
return Qt.point(pos.x, pos.y)
}
+ function mapAFromGlobalPoint(x, y) {
+ var pos = itemA.mapFromGlobal(Qt.point(x, y))
+ return Qt.point(pos.x, pos.y)
+ }
+
function mapOrphanToGlobal(x, y) {
var obj = itemComponent.createObject(null);
var pos = obj.mapToGlobal(x, y)
diff --git a/tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml b/tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml
index 2b856a27fc..c66d1e89b6 100644
--- a/tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml
+++ b/tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml
@@ -45,11 +45,21 @@ Item {
return Qt.rect(pos.x, pos.y, pos.width, pos.height)
}
+ function mapAToBRect(x, y, w, h) {
+ var pos = itemA.mapToItem(itemB, Qt.rect(x, y, w, h))
+ return Qt.rect(pos.x, pos.y, pos.width, pos.height)
+ }
+
function mapAFromB(x, y, w, h) {
var pos = itemA.mapFromItem(itemB, x, y, w, h)
return Qt.rect(pos.x, pos.y, pos.width, pos.height)
}
+ function mapAFromBRect(x, y, w, h) {
+ var pos = itemA.mapFromItem(itemB, Qt.rect(x, y, w, h))
+ return Qt.rect(pos.x, pos.y, pos.width, pos.height)
+ }
+
function mapAToNull(x, y, w, h) {
var pos = itemA.mapToItem(null, x, y, w, h)
return Qt.rect(pos.x, pos.y, pos.width, pos.height)
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index 607cf91bfe..a1b4a70217 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -2391,10 +2391,18 @@ void tst_QQuickItem::mapCoordinates()
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToItem(b, QPointF(x, y)));
+ QVERIFY(QMetaObject::invokeMethod(root, "mapAToBPoint",
+ Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
+ QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToItem(b, QPointF(x, y)));
+
QVERIFY(QMetaObject::invokeMethod(root, "mapAFromB",
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromItem(b, QPointF(x, y)));
+ QVERIFY(QMetaObject::invokeMethod(root, "mapAFromBPoint",
+ Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
+ QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromItem(b, QPointF(x, y)));
+
QVERIFY(QMetaObject::invokeMethod(root, "mapAToNull",
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToScene(QPointF(x, y)));
@@ -2407,10 +2415,18 @@ void tst_QQuickItem::mapCoordinates()
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToGlobal(QPointF(x, y)));
+ QVERIFY(QMetaObject::invokeMethod(root, "mapAToGlobalPoint",
+ Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
+ QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapToGlobal(QPointF(x, y)));
+
QVERIFY(QMetaObject::invokeMethod(root, "mapAFromGlobal",
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromGlobal(QPointF(x, y)));
+ QVERIFY(QMetaObject::invokeMethod(root, "mapAFromGlobalPoint",
+ Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
+ QCOMPARE(result.value<QPointF>(), qobject_cast<QQuickItem*>(a)->mapFromGlobal(QPointF(x, y)));
+
// for orphans we are primarily testing that we don't crash.
// when orphaned the final position is the original position of the item translated by x,y
QVERIFY(QMetaObject::invokeMethod(root, "mapOrphanToGlobal",
@@ -2472,10 +2488,18 @@ void tst_QQuickItem::mapCoordinatesRect()
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectToItem(b, QRectF(x, y, width, height)));
+ QVERIFY(QMetaObject::invokeMethod(root, "mapAToBRect",
+ Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
+ QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectToItem(b, QRectF(x, y, width, height)));
+
QVERIFY(QMetaObject::invokeMethod(root, "mapAFromB",
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectFromItem(b, QRectF(x, y, width, height)));
+ QVERIFY(QMetaObject::invokeMethod(root, "mapAFromBRect",
+ Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
+ QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectFromItem(b, QRectF(x, y, width, height)));
+
QVERIFY(QMetaObject::invokeMethod(root, "mapAToNull",
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectToScene(QRectF(x, y, width, height)));
diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST
index 1f3736328a..6ef69550a4 100644
--- a/tests/auto/quick/qquicklistview/BLACKLIST
+++ b/tests/auto/quick/qquicklistview/BLACKLIST
@@ -5,10 +5,10 @@ opensuse-leap
[populateTransitions]
opensuse-42.1
[contentHeightWithDelayRemove]
-osx-10.12
+macos
#QTBUG-75960
#QTBUG-76652
[currentIndex]
-osx-10.12
+macos
opensuse-leap
ubuntu-18.04
diff --git a/tests/auto/quick/qquicktext/BLACKLIST b/tests/auto/quick/qquicktext/BLACKLIST
index 594f9af3b3..b551575e9d 100644
--- a/tests/auto/quick/qquicktext/BLACKLIST
+++ b/tests/auto/quick/qquicktext/BLACKLIST
@@ -1,7 +1,7 @@
[dependentImplicitSizes]
b2qt
qemu
-osx-10.12
+macos
[fontSizeMode]
opensuse-42.1
[contentSize]
diff --git a/tests/manual/nodetypes_ng/buildshaders.bat b/tests/manual/nodetypes_ng/compile.bat
index 328b216c07..328b216c07 100755
--- a/tests/manual/nodetypes_ng/buildshaders.bat
+++ b/tests/manual/nodetypes_ng/compile.bat
diff --git a/tests/manual/nodetypes_ng/shadow_pass1.frag.qsb b/tests/manual/nodetypes_ng/shadow_pass1.frag.qsb
index f90265a997..4c913fee08 100644
--- a/tests/manual/nodetypes_ng/shadow_pass1.frag.qsb
+++ b/tests/manual/nodetypes_ng/shadow_pass1.frag.qsb
Binary files differ
diff --git a/tests/manual/nodetypes_ng/shadow_pass2.frag.qsb b/tests/manual/nodetypes_ng/shadow_pass2.frag.qsb
index 9608763b61..4f6e6634e7 100644
--- a/tests/manual/nodetypes_ng/shadow_pass2.frag.qsb
+++ b/tests/manual/nodetypes_ng/shadow_pass2.frag.qsb
Binary files differ
diff --git a/tests/manual/nodetypes_ng/wobble.frag.qsb b/tests/manual/nodetypes_ng/wobble.frag.qsb
index 7d3105fd3c..f1766f4363 100644
--- a/tests/manual/nodetypes_ng/wobble.frag.qsb
+++ b/tests/manual/nodetypes_ng/wobble.frag.qsb
Binary files differ
diff --git a/tests/manual/nodetypes_ng/wobble.vert.qsb b/tests/manual/nodetypes_ng/wobble.vert.qsb
index 92b8ba9703..2715c84616 100644
--- a/tests/manual/nodetypes_ng/wobble.vert.qsb
+++ b/tests/manual/nodetypes_ng/wobble.vert.qsb
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/basic.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/basic.frag
index c6da52fd32..15459ffdb9 100644
--- a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/basic.frag
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/basic.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/cmyk.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/cmyk.frag
index e9c48edbb9..5ef0333b6b 100644
--- a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/cmyk.frag
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/cmyk.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/culling.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/culling.frag
index 6f44fff112..edf2d11a93 100644
--- a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/culling.frag
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/culling.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/edge.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/edge.frag
index 01a1d1cb3d..aecaa621ef 100644
--- a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/edge.frag
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/edge.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient.frag
index 78ac8a9c95..ef7a9c10ca 100644
--- a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient.frag
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient2.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient2.frag
index 364fffab52..ca58580786 100644
--- a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient2.frag
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient2.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient3.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient3.frag
index 42bebf490a..e1fc8b0ce8 100644
--- a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient3.frag
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient3.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient4.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient4.frag
index ed31582cf9..2e0b809d7d 100644
--- a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient4.frag
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient4.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient5.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient5.frag
index 7fe041f0ae..106c2c5515 100644
--- a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient5.frag
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/gradient5.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/shadow.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/shadow.frag
index cb3428b75f..788a047ab0 100644
--- a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/shadow.frag
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/shadow.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/stencil.frag b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/stencil.frag
index ccf3633d64..e3907a90d2 100644
--- a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/stencil.frag
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/stencil.frag
Binary files differ
diff --git a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/wave.vert b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/wave.vert
index 04850feb27..14cb4e768f 100644
--- a/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/wave.vert
+++ b/tests/manual/scenegraph_lancelot/data/shared/shaders/+qsb/wave.vert
Binary files differ
diff --git a/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in b/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in
index 6cdfaf8f6f..f92b8d295d 100644
--- a/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in
+++ b/tools/qmlimportscanner/Qt5QmlImportScannerConfig.cmake.in
@@ -182,3 +182,13 @@ but this file does not exist. Possible reasons include:
endif()
!!ENDIF // !isEmpty(CMAKE_STATIC_TYPE)
endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_import_qml_plugins)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
+ qt5_import_qml_plugins(${ARGV})
+ elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_import_qml_plugins(${ARGV})
+ endif()
+ endfunction()
+endif()